From d7ed39beabb105c5e91e1ab233c83e75d08faadc Mon Sep 17 00:00:00 2001 From: Adam Harwayne Date: Mon, 28 Jan 2019 09:13:25 -0800 Subject: [PATCH 001/221] Initial API outline for Broker. --- pkg/apis/eventing/v1alpha1/broker_defaults.go | 71 +++++++ .../eventing/v1alpha1/broker_defaults_test.go | 25 +++ pkg/apis/eventing/v1alpha1/broker_types.go | 137 ++++++++++++++ .../eventing/v1alpha1/broker_validation.go | 92 +++++++++ .../v1alpha1/zz_generated.deepcopy.go | 170 ++++++++++++++++- .../typed/eventing/v1alpha1/broker.go | 174 ++++++++++++++++++ .../eventing/v1alpha1/eventing_client.go | 5 + .../eventing/v1alpha1/fake/fake_broker.go | 140 ++++++++++++++ .../v1alpha1/fake/fake_eventing_client.go | 4 + .../eventing/v1alpha1/generated_expansion.go | 2 + .../eventing/v1alpha1/broker.go | 89 +++++++++ .../eventing/v1alpha1/interface.go | 7 + .../informers/externalversions/generic.go | 2 + .../listers/eventing/v1alpha1/broker.go | 94 ++++++++++ .../eventing/v1alpha1/expansion_generated.go | 8 + 15 files changed, 1010 insertions(+), 10 deletions(-) create mode 100644 pkg/apis/eventing/v1alpha1/broker_defaults.go create mode 100644 pkg/apis/eventing/v1alpha1/broker_defaults_test.go create mode 100644 pkg/apis/eventing/v1alpha1/broker_types.go create mode 100644 pkg/apis/eventing/v1alpha1/broker_validation.go create mode 100644 pkg/client/clientset/versioned/typed/eventing/v1alpha1/broker.go create mode 100644 pkg/client/clientset/versioned/typed/eventing/v1alpha1/fake/fake_broker.go create mode 100644 pkg/client/informers/externalversions/eventing/v1alpha1/broker.go create mode 100644 pkg/client/listers/eventing/v1alpha1/broker.go diff --git a/pkg/apis/eventing/v1alpha1/broker_defaults.go b/pkg/apis/eventing/v1alpha1/broker_defaults.go new file mode 100644 index 00000000000..fe795921b50 --- /dev/null +++ b/pkg/apis/eventing/v1alpha1/broker_defaults.go @@ -0,0 +1,71 @@ +/* +Copyright 2019 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + +const ( + brokerLabel = "eventing.knative.dev/broker" +) + +func (b *Broker) SetDefaults() { + b.Spec.SetDefaults(b.Name) +} + +func (bs *BrokerSpec) SetDefaults(brokerName string) { + if bs.Selector == nil { + bs.Selector = defaultBrokerSpecSelector(brokerName) + } + if bs.ChannelTemplate == nil { + bs.ChannelTemplate = defaultBrokerSpecChannelTemplate(brokerName) + } + if len(bs.SubscribableResources) == 0 { + bs.SubscribableResources = defaultBrokerSpecSubscribableResources() + } +} + +func defaultBrokerLabels(brokerName string) map[string]string { + return map[string]string{ + brokerLabel: brokerName, + } +} + +func defaultBrokerSpecSelector(brokerName string) *v1.LabelSelector { + return &v1.LabelSelector{ + MatchLabels: defaultBrokerLabels(brokerName), + } +} + +func defaultBrokerSpecChannelTemplate(brokerName string) *ChannelTemplateSpec { + return &ChannelTemplateSpec{ + metadata: v1.ObjectMeta{ + Labels: defaultBrokerLabels(brokerName), + }, + // Spec is left blank so that the created Channel defaulter will default the provisioner + // and arguments when the Channel is created. + } +} + +func defaultBrokerSpecSubscribableResources() []v1.GroupVersionKind { + return []v1.GroupVersionKind{ + { + Group: "eventing.knative.dev", + Version: "v1alpha1", + Kind: "Channel", + }, + } +} diff --git a/pkg/apis/eventing/v1alpha1/broker_defaults_test.go b/pkg/apis/eventing/v1alpha1/broker_defaults_test.go new file mode 100644 index 00000000000..b27c6b2d7c6 --- /dev/null +++ b/pkg/apis/eventing/v1alpha1/broker_defaults_test.go @@ -0,0 +1,25 @@ +/* +Copyright 2019 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import "testing" + +// No-op test because method does nothing. +func TestBrokerDefaults(t *testing.T) { + b := Broker{} + b.SetDefaults() +} diff --git a/pkg/apis/eventing/v1alpha1/broker_types.go b/pkg/apis/eventing/v1alpha1/broker_types.go new file mode 100644 index 00000000000..51216de7f89 --- /dev/null +++ b/pkg/apis/eventing/v1alpha1/broker_types.go @@ -0,0 +1,137 @@ +/* + * Copyright 2019 The Knative Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package v1alpha1 + +import ( + "github.com/knative/pkg/apis" + duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" + "github.com/knative/pkg/webhook" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// Broker is an abstract resource that implements the Addressable contract. +// The Provisioner provisions infrastructure to accepts events and +// deliver to Subscriptions. +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"` +} + +// Check that Broker can be validated, can be defaulted, and has immutable fields. +var _ apis.Validatable = (*Broker)(nil) +var _ apis.Defaultable = (*Broker)(nil) +var _ apis.Immutable = (*Broker)(nil) +var _ runtime.Object = (*Broker)(nil) +var _ webhook.GenericCRD = (*Broker)(nil) + +// BrokerSpec specifies the Provisioner backing a channel and the configuration +// arguments for a Broker. +type BrokerSpec struct { + Selector *metav1.LabelSelector `json:"selector,omitempty"` + ChannelTemplate *ChannelTemplateSpec `json:"channelTemplate,omitempty"` + SubscribableResources []metav1.GroupVersionKind `json:"subscribableResources,omitempty"` +} + +type ChannelTemplateSpec struct { + metadata metav1.ObjectMeta `json:"metadata,omitempty"` + Spec *ChannelSpec `json:"spec,omitempty"` +} + +var brokerCondSet = duckv1alpha1.NewLivingConditionSet(BrokerConditionChannelTemplateSelector, BrokerConditionSubscribableResourcesExist) + +// BrokerStatus represents the current state of a Broker. +type BrokerStatus struct { + // ObservedGeneration is the most recent generation observed for this Broker. + // It corresponds to the Broker's generation, which is updated on mutation by + // the API Server. + // TODO: The above comment is only true once + // https://github.com/kubernetes/kubernetes/issues/58778 is fixed. + // +optional + ObservedGeneration int64 `json:"observedGeneration,omitempty"` + + // Represents the latest available observations of a channel's current state. + // +optional + // +patchMergeKey=type + // +patchStrategy=merge + Conditions duckv1alpha1.Conditions `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"` +} + +const ( + // BrokerConditionReady has status True when the Broker is ready to + // accept traffic. + BrokerConditionReady = duckv1alpha1.ConditionReady + + BrokerConditionChannelTemplateSelector duckv1alpha1.ConditionType = "ChannelTemplateSelector" + + BrokerConditionSubscribableResourcesExist duckv1alpha1.ConditionType = "SubscribableResourcesExist" +) + +// GetCondition returns the condition currently associated with the given type, or nil. +func (bs *BrokerStatus) GetCondition(t duckv1alpha1.ConditionType) *duckv1alpha1.Condition { + return chanCondSet.Manage(bs).GetCondition(t) +} + +// IsReady returns true if the resource is ready overall. +func (bs *BrokerStatus) IsReady() bool { + return chanCondSet.Manage(bs).IsHappy() +} + +// InitializeConditions sets relevant unset conditions to Unknown state. +func (bs *BrokerStatus) InitializeConditions() { + chanCondSet.Manage(bs).InitializeConditions() +} + +func (bs *BrokerStatus) MarkChannelTemplateMatchesSelector() { + chanCondSet.Manage(bs).MarkTrue(BrokerConditionChannelTemplateSelector) +} + +func (bs *BrokerStatus) MarkChannelTemplateDoesNotMatchSelector() { + chanCondSet.Manage(bs).MarkFalse(BrokerConditionChannelTemplateSelector, "selectorDoesNotMatchTemplate", "`spec.selector` does not match `spec.channelTempalte.meta.labels`") +} + +// MarkProvisioned sets BrokerConditionProvisioned condition to True state. +func (bs *BrokerStatus) MarkSubscribableResourcesExist() { + chanCondSet.Manage(bs).MarkTrue(BrokerConditionSubscribableResourcesExist) +} + +// MarkNotProvisioned sets BrokerConditionProvisioned condition to False state. +func (bs *BrokerStatus) MarkSubscribableResourcesDoNotExist(reason, messageFormat string, messageA ...interface{}) { + chanCondSet.Manage(bs).MarkFalse(BrokerConditionSubscribableResourcesExist, reason, messageFormat, messageA...) +} + +// +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"` +} diff --git a/pkg/apis/eventing/v1alpha1/broker_validation.go b/pkg/apis/eventing/v1alpha1/broker_validation.go new file mode 100644 index 00000000000..72c7fa3c7a2 --- /dev/null +++ b/pkg/apis/eventing/v1alpha1/broker_validation.go @@ -0,0 +1,92 @@ +/* +Copyright 2019 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + "fmt" + + "github.com/google/go-cmp/cmp" + "github.com/knative/pkg/apis" + "k8s.io/apimachinery/pkg/api/equality" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func (b *Broker) Validate() *apis.FieldError { + return b.Spec.Validate().ViaField("spec") +} + +func (bs *BrokerSpec) Validate() *apis.FieldError { + var errs *apis.FieldError + if isSelectorNotPresentOrEmpty(bs.Selector) { + fe := apis.ErrMissingField("selector") + fe.Details = "the Broker must have a selector" + errs = errs.Also(fe) + } + + if bs.ChannelTemplate == nil { + fe := apis.ErrMissingField("channelTemplate") + fe.Details = "the Broker must have a channelTemplate" + errs = errs.Also(fe) + } else if !selectorMatchesTemplateLabels(bs.Selector, bs.ChannelTemplate) { + fe := apis.ErrInvalidValue(fmt.Sprint(bs.ChannelTemplate.metadata.Labels), "channelTemplate.metadata.labels") + errs = errs.Also(fe) + } + + if !channelsInSubscribableResources(bs.SubscribableResources) { + fe := apis.ErrInvalidValue(fmt.Sprint(bs.SubscribableResources), "subscribableResources") + errs = errs.Also(fe) + } + + return errs +} + +func isSelectorNotPresentOrEmpty(s *v1.LabelSelector) bool { + return s == nil || equality.Semantic.DeepEqual(s, &v1.LabelSelector{}) +} + +func selectorMatchesTemplateLabels(s *v1.LabelSelector, ct *ChannelTemplateSpec) bool { + // TODO Improve this so it supports something other than direct label equality. + return equality.Semantic.DeepEqual(s.MatchLabels, ct.metadata.Labels) +} + +func channelsInSubscribableResources(sr []v1.GroupVersionKind) bool { + for _, r := range sr { + if r.Group == "eventing.knative.dev" && r.Version == "v1alpha1" && r.Kind == "Channel" { + return true + } + } + return false +} + +func (b *Broker) CheckImmutableFields(og apis.Immutable) *apis.FieldError { + original, ok := og.(*Broker) + if !ok { + return &apis.FieldError{Message: "The provided original was not a Broker"} + } + if original == nil { + return nil + } + + if diff := cmp.Diff(original.Spec.Selector, b.Spec.Selector); diff != "" { + return &apis.FieldError{ + Message: "Immutable fields changed (-old +new)", + Paths: []string{"spec", "selector"}, + Details: diff, + } + } + return nil +} diff --git a/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go index d43df63bdb2..6481321c20e 100644 --- a/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go @@ -21,12 +21,136 @@ limitations under the License. package v1alpha1 import ( - duck_v1alpha1 "github.com/knative/eventing/pkg/apis/duck/v1alpha1" - apis_duck_v1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" - v1 "k8s.io/api/core/v1" + apis_duck_v1alpha1 "github.com/knative/eventing/pkg/apis/duck/v1alpha1" + duck_v1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" + core_v1 "k8s.io/api/core/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" ) +// 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 + out.ListMeta = in.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.Selector != nil { + in, out := &in.Selector, &out.Selector + if *in == nil { + *out = nil + } else { + *out = new(v1.LabelSelector) + (*in).DeepCopyInto(*out) + } + } + if in.ChannelTemplate != nil { + in, out := &in.ChannelTemplate, &out.ChannelTemplate + if *in == nil { + *out = nil + } else { + *out = new(ChannelTemplateSpec) + (*in).DeepCopyInto(*out) + } + } + if in.SubscribableResources != nil { + in, out := &in.SubscribableResources, &out.SubscribableResources + *out = make([]v1.GroupVersionKind, len(*in)) + copy(*out, *in) + } + 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 + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make(duck_v1alpha1.Conditions, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + 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 *Channel) DeepCopyInto(out *Channel) { *out = *in @@ -96,7 +220,7 @@ func (in *ChannelSpec) DeepCopyInto(out *ChannelSpec) { if *in == nil { *out = nil } else { - *out = new(v1.ObjectReference) + *out = new(core_v1.ObjectReference) **out = **in } } @@ -114,7 +238,7 @@ func (in *ChannelSpec) DeepCopyInto(out *ChannelSpec) { if *in == nil { *out = nil } else { - *out = new(duck_v1alpha1.Subscribable) + *out = new(apis_duck_v1alpha1.Subscribable) (*in).DeepCopyInto(*out) } } @@ -137,7 +261,7 @@ func (in *ChannelStatus) DeepCopyInto(out *ChannelStatus) { out.Address = in.Address if in.Conditions != nil { in, out := &in.Conditions, &out.Conditions - *out = make(apis_duck_v1alpha1.Conditions, len(*in)) + *out = make(duck_v1alpha1.Conditions, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } @@ -164,6 +288,32 @@ func (in *ChannelStatus) DeepCopy() *ChannelStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ChannelTemplateSpec) DeepCopyInto(out *ChannelTemplateSpec) { + *out = *in + in.metadata.DeepCopyInto(&out.metadata) + if in.Spec != nil { + in, out := &in.Spec, &out.Spec + if *in == nil { + *out = nil + } else { + *out = new(ChannelSpec) + (*in).DeepCopyInto(*out) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ChannelTemplateSpec. +func (in *ChannelTemplateSpec) DeepCopy() *ChannelTemplateSpec { + if in == nil { + return nil + } + out := new(ChannelTemplateSpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ClusterChannelProvisioner) DeepCopyInto(out *ClusterChannelProvisioner) { *out = *in @@ -246,7 +396,7 @@ func (in *ClusterChannelProvisionerStatus) DeepCopyInto(out *ClusterChannelProvi *out = *in if in.Conditions != nil { in, out := &in.Conditions, &out.Conditions - *out = make(apis_duck_v1alpha1.Conditions, len(*in)) + *out = make(duck_v1alpha1.Conditions, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } @@ -272,7 +422,7 @@ func (in *ReplyStrategy) DeepCopyInto(out *ReplyStrategy) { if *in == nil { *out = nil } else { - *out = new(v1.ObjectReference) + *out = new(core_v1.ObjectReference) **out = **in } } @@ -297,7 +447,7 @@ func (in *SubscriberSpec) DeepCopyInto(out *SubscriberSpec) { if *in == nil { *out = nil } else { - *out = new(v1.ObjectReference) + *out = new(core_v1.ObjectReference) **out = **in } } @@ -424,7 +574,7 @@ func (in *SubscriptionStatus) DeepCopyInto(out *SubscriptionStatus) { *out = *in if in.Conditions != nil { in, out := &in.Conditions, &out.Conditions - *out = make(apis_duck_v1alpha1.Conditions, len(*in)) + *out = make(duck_v1alpha1.Conditions, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } diff --git a/pkg/client/clientset/versioned/typed/eventing/v1alpha1/broker.go b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/broker.go new file mode 100644 index 00000000000..7ae965feb0e --- /dev/null +++ b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/broker.go @@ -0,0 +1,174 @@ +/* +Copyright 2018 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + v1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" + scheme "github.com/knative/eventing/pkg/client/clientset/versioned/scheme" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" +) + +// 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(*v1alpha1.Broker) (*v1alpha1.Broker, error) + Update(*v1alpha1.Broker) (*v1alpha1.Broker, error) + UpdateStatus(*v1alpha1.Broker) (*v1alpha1.Broker, error) + Delete(name string, options *v1.DeleteOptions) error + DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error + Get(name string, options v1.GetOptions) (*v1alpha1.Broker, error) + List(opts v1.ListOptions) (*v1alpha1.BrokerList, error) + Watch(opts v1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.Broker, err error) + BrokerExpansion +} + +// brokers implements BrokerInterface +type brokers struct { + client rest.Interface + ns string +} + +// newBrokers returns a Brokers +func newBrokers(c *EventingV1alpha1Client, 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 v1.GetOptions) (result *v1alpha1.Broker, err error) { + result = &v1alpha1.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 v1.ListOptions) (result *v1alpha1.BrokerList, err error) { + result = &v1alpha1.BrokerList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("brokers"). + VersionedParams(&opts, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested brokers. +func (c *brokers) Watch(opts v1.ListOptions) (watch.Interface, error) { + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("brokers"). + VersionedParams(&opts, scheme.ParameterCodec). + 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 *v1alpha1.Broker) (result *v1alpha1.Broker, err error) { + result = &v1alpha1.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 *v1alpha1.Broker) (result *v1alpha1.Broker, err error) { + result = &v1alpha1.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 *v1alpha1.Broker) (result *v1alpha1.Broker, err error) { + result = &v1alpha1.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 *v1.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 *v1.DeleteOptions, listOptions v1.ListOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("brokers"). + VersionedParams(&listOptions, scheme.ParameterCodec). + 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 *v1alpha1.Broker, err error) { + result = &v1alpha1.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/v1alpha1/eventing_client.go b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/eventing_client.go index ef337f70bf0..8a2796c7417 100644 --- a/pkg/client/clientset/versioned/typed/eventing/v1alpha1/eventing_client.go +++ b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/eventing_client.go @@ -27,6 +27,7 @@ import ( type EventingV1alpha1Interface interface { RESTClient() rest.Interface + BrokersGetter ChannelsGetter ClusterChannelProvisionersGetter SubscriptionsGetter @@ -37,6 +38,10 @@ type EventingV1alpha1Client struct { restClient rest.Interface } +func (c *EventingV1alpha1Client) Brokers(namespace string) BrokerInterface { + return newBrokers(c, namespace) +} + func (c *EventingV1alpha1Client) Channels(namespace string) ChannelInterface { return newChannels(c, namespace) } diff --git a/pkg/client/clientset/versioned/typed/eventing/v1alpha1/fake/fake_broker.go b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/fake/fake_broker.go new file mode 100644 index 00000000000..c7b30557ec1 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/fake/fake_broker.go @@ -0,0 +1,140 @@ +/* +Copyright 2018 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT 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 ( + v1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" + 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" +) + +// FakeBrokers implements BrokerInterface +type FakeBrokers struct { + Fake *FakeEventingV1alpha1 + ns string +} + +var brokersResource = schema.GroupVersionResource{Group: "eventing.knative.dev", Version: "v1alpha1", Resource: "brokers"} + +var brokersKind = schema.GroupVersionKind{Group: "eventing.knative.dev", Version: "v1alpha1", 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 *v1alpha1.Broker, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(brokersResource, c.ns, name), &v1alpha1.Broker{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.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 *v1alpha1.BrokerList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(brokersResource, brokersKind, c.ns, opts), &v1alpha1.BrokerList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.BrokerList{ListMeta: obj.(*v1alpha1.BrokerList).ListMeta} + for _, item := range obj.(*v1alpha1.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 *v1alpha1.Broker) (result *v1alpha1.Broker, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(brokersResource, c.ns, broker), &v1alpha1.Broker{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.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 *v1alpha1.Broker) (result *v1alpha1.Broker, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(brokersResource, c.ns, broker), &v1alpha1.Broker{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.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 *v1alpha1.Broker) (*v1alpha1.Broker, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(brokersResource, "status", c.ns, broker), &v1alpha1.Broker{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.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), &v1alpha1.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, &v1alpha1.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 *v1alpha1.Broker, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(brokersResource, c.ns, name, data, subresources...), &v1alpha1.Broker{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.Broker), err +} diff --git a/pkg/client/clientset/versioned/typed/eventing/v1alpha1/fake/fake_eventing_client.go b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/fake/fake_eventing_client.go index 0080c07b8d4..68998cd28f5 100644 --- a/pkg/client/clientset/versioned/typed/eventing/v1alpha1/fake/fake_eventing_client.go +++ b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/fake/fake_eventing_client.go @@ -28,6 +28,10 @@ type FakeEventingV1alpha1 struct { *testing.Fake } +func (c *FakeEventingV1alpha1) Brokers(namespace string) v1alpha1.BrokerInterface { + return &FakeBrokers{c, namespace} +} + func (c *FakeEventingV1alpha1) Channels(namespace string) v1alpha1.ChannelInterface { return &FakeChannels{c, namespace} } diff --git a/pkg/client/clientset/versioned/typed/eventing/v1alpha1/generated_expansion.go b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/generated_expansion.go index fcef70e765c..94933cfbc74 100644 --- a/pkg/client/clientset/versioned/typed/eventing/v1alpha1/generated_expansion.go +++ b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/generated_expansion.go @@ -18,6 +18,8 @@ limitations under the License. package v1alpha1 +type BrokerExpansion interface{} + type ChannelExpansion interface{} type ClusterChannelProvisionerExpansion interface{} diff --git a/pkg/client/informers/externalversions/eventing/v1alpha1/broker.go b/pkg/client/informers/externalversions/eventing/v1alpha1/broker.go new file mode 100644 index 00000000000..f9dcaf534b3 --- /dev/null +++ b/pkg/client/informers/externalversions/eventing/v1alpha1/broker.go @@ -0,0 +1,89 @@ +/* +Copyright 2018 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + time "time" + + eventing_v1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" + versioned "github.com/knative/eventing/pkg/client/clientset/versioned" + internalinterfaces "github.com/knative/eventing/pkg/client/informers/externalversions/internalinterfaces" + v1alpha1 "github.com/knative/eventing/pkg/client/listers/eventing/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" +) + +// BrokerInformer provides access to a shared informer and lister for +// Brokers. +type BrokerInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1alpha1.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 v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.EventingV1alpha1().Brokers(namespace).List(options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.EventingV1alpha1().Brokers(namespace).Watch(options) + }, + }, + &eventing_v1alpha1.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(&eventing_v1alpha1.Broker{}, f.defaultInformer) +} + +func (f *brokerInformer) Lister() v1alpha1.BrokerLister { + return v1alpha1.NewBrokerLister(f.Informer().GetIndexer()) +} diff --git a/pkg/client/informers/externalversions/eventing/v1alpha1/interface.go b/pkg/client/informers/externalversions/eventing/v1alpha1/interface.go index 15bebacbe7f..9d7b654e259 100644 --- a/pkg/client/informers/externalversions/eventing/v1alpha1/interface.go +++ b/pkg/client/informers/externalversions/eventing/v1alpha1/interface.go @@ -24,6 +24,8 @@ import ( // Interface provides access to all the informers in this group version. type Interface interface { + // Brokers returns a BrokerInformer. + Brokers() BrokerInformer // Channels returns a ChannelInformer. Channels() ChannelInformer // ClusterChannelProvisioners returns a ClusterChannelProvisionerInformer. @@ -43,6 +45,11 @@ func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakList 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} +} + // Channels returns a ChannelInformer. func (v *version) Channels() ChannelInformer { return &channelInformer{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 eb07d8f78ef..8e99e8692d4 100644 --- a/pkg/client/informers/externalversions/generic.go +++ b/pkg/client/informers/externalversions/generic.go @@ -53,6 +53,8 @@ func (f *genericInformer) Lister() cache.GenericLister { func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) { switch resource { // Group=eventing.knative.dev, Version=v1alpha1 + case v1alpha1.SchemeGroupVersion.WithResource("brokers"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Eventing().V1alpha1().Brokers().Informer()}, nil case v1alpha1.SchemeGroupVersion.WithResource("channels"): return &genericInformer{resource: resource.GroupResource(), informer: f.Eventing().V1alpha1().Channels().Informer()}, nil case v1alpha1.SchemeGroupVersion.WithResource("clusterchannelprovisioners"): diff --git a/pkg/client/listers/eventing/v1alpha1/broker.go b/pkg/client/listers/eventing/v1alpha1/broker.go new file mode 100644 index 00000000000..4916e953b2f --- /dev/null +++ b/pkg/client/listers/eventing/v1alpha1/broker.go @@ -0,0 +1,94 @@ +/* +Copyright 2018 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + v1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" +) + +// BrokerLister helps list Brokers. +type BrokerLister interface { + // List lists all Brokers in the indexer. + List(selector labels.Selector) (ret []*v1alpha1.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 []*v1alpha1.Broker, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.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 []*v1alpha1.Broker, err error) + // Get retrieves the Broker from the indexer for a given namespace and name. + Get(name string) (*v1alpha1.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 []*v1alpha1.Broker, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.Broker)) + }) + return ret, err +} + +// Get retrieves the Broker from the indexer for a given namespace and name. +func (s brokerNamespaceLister) Get(name string) (*v1alpha1.Broker, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1alpha1.Resource("broker"), name) + } + return obj.(*v1alpha1.Broker), nil +} diff --git a/pkg/client/listers/eventing/v1alpha1/expansion_generated.go b/pkg/client/listers/eventing/v1alpha1/expansion_generated.go index ce1c8af2399..2b4ca79dad1 100644 --- a/pkg/client/listers/eventing/v1alpha1/expansion_generated.go +++ b/pkg/client/listers/eventing/v1alpha1/expansion_generated.go @@ -18,6 +18,14 @@ limitations under the License. package v1alpha1 +// BrokerListerExpansion allows custom methods to be added to +// BrokerLister. +type BrokerListerExpansion interface{} + +// BrokerNamespaceListerExpansion allows custom methods to be added to +// BrokerNamespaceLister. +type BrokerNamespaceListerExpansion interface{} + // ChannelListerExpansion allows custom methods to be added to // ChannelLister. type ChannelListerExpansion interface{} From 080f5eb8c30b2a93c49d264777262d38d99ff3e3 Mon Sep 17 00:00:00 2001 From: Adam Harwayne Date: Mon, 28 Jan 2019 09:27:12 -0800 Subject: [PATCH 002/221] Metadata is exported --- pkg/apis/eventing/v1alpha1/broker_defaults.go | 2 +- pkg/apis/eventing/v1alpha1/broker_types.go | 16 ++++++++-------- pkg/apis/eventing/v1alpha1/broker_validation.go | 4 ++-- .../eventing/v1alpha1/zz_generated.deepcopy.go | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/pkg/apis/eventing/v1alpha1/broker_defaults.go b/pkg/apis/eventing/v1alpha1/broker_defaults.go index fe795921b50..c8a23a6eda5 100644 --- a/pkg/apis/eventing/v1alpha1/broker_defaults.go +++ b/pkg/apis/eventing/v1alpha1/broker_defaults.go @@ -52,7 +52,7 @@ func defaultBrokerSpecSelector(brokerName string) *v1.LabelSelector { func defaultBrokerSpecChannelTemplate(brokerName string) *ChannelTemplateSpec { return &ChannelTemplateSpec{ - metadata: v1.ObjectMeta{ + Metadata: v1.ObjectMeta{ Labels: defaultBrokerLabels(brokerName), }, // Spec is left blank so that the created Channel defaulter will default the provisioner diff --git a/pkg/apis/eventing/v1alpha1/broker_types.go b/pkg/apis/eventing/v1alpha1/broker_types.go index 51216de7f89..08462a1fded 100644 --- a/pkg/apis/eventing/v1alpha1/broker_types.go +++ b/pkg/apis/eventing/v1alpha1/broker_types.go @@ -60,7 +60,7 @@ type BrokerSpec struct { } type ChannelTemplateSpec struct { - metadata metav1.ObjectMeta `json:"metadata,omitempty"` + Metadata metav1.ObjectMeta `json:"metadata,omitempty"` Spec *ChannelSpec `json:"spec,omitempty"` } @@ -95,35 +95,35 @@ const ( // GetCondition returns the condition currently associated with the given type, or nil. func (bs *BrokerStatus) GetCondition(t duckv1alpha1.ConditionType) *duckv1alpha1.Condition { - return chanCondSet.Manage(bs).GetCondition(t) + return brokerCondSet.Manage(bs).GetCondition(t) } // IsReady returns true if the resource is ready overall. func (bs *BrokerStatus) IsReady() bool { - return chanCondSet.Manage(bs).IsHappy() + return brokerCondSet.Manage(bs).IsHappy() } // InitializeConditions sets relevant unset conditions to Unknown state. func (bs *BrokerStatus) InitializeConditions() { - chanCondSet.Manage(bs).InitializeConditions() + brokerCondSet.Manage(bs).InitializeConditions() } func (bs *BrokerStatus) MarkChannelTemplateMatchesSelector() { - chanCondSet.Manage(bs).MarkTrue(BrokerConditionChannelTemplateSelector) + brokerCondSet.Manage(bs).MarkTrue(BrokerConditionChannelTemplateSelector) } func (bs *BrokerStatus) MarkChannelTemplateDoesNotMatchSelector() { - chanCondSet.Manage(bs).MarkFalse(BrokerConditionChannelTemplateSelector, "selectorDoesNotMatchTemplate", "`spec.selector` does not match `spec.channelTempalte.meta.labels`") + brokerCondSet.Manage(bs).MarkFalse(BrokerConditionChannelTemplateSelector, "selectorDoesNotMatchTemplate", "`spec.selector` does not match `spec.channelTempalte.meta.labels`") } // MarkProvisioned sets BrokerConditionProvisioned condition to True state. func (bs *BrokerStatus) MarkSubscribableResourcesExist() { - chanCondSet.Manage(bs).MarkTrue(BrokerConditionSubscribableResourcesExist) + brokerCondSet.Manage(bs).MarkTrue(BrokerConditionSubscribableResourcesExist) } // MarkNotProvisioned sets BrokerConditionProvisioned condition to False state. func (bs *BrokerStatus) MarkSubscribableResourcesDoNotExist(reason, messageFormat string, messageA ...interface{}) { - chanCondSet.Manage(bs).MarkFalse(BrokerConditionSubscribableResourcesExist, reason, messageFormat, messageA...) + brokerCondSet.Manage(bs).MarkFalse(BrokerConditionSubscribableResourcesExist, reason, messageFormat, messageA...) } // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object diff --git a/pkg/apis/eventing/v1alpha1/broker_validation.go b/pkg/apis/eventing/v1alpha1/broker_validation.go index 72c7fa3c7a2..98d31a4b9cd 100644 --- a/pkg/apis/eventing/v1alpha1/broker_validation.go +++ b/pkg/apis/eventing/v1alpha1/broker_validation.go @@ -42,7 +42,7 @@ func (bs *BrokerSpec) Validate() *apis.FieldError { fe.Details = "the Broker must have a channelTemplate" errs = errs.Also(fe) } else if !selectorMatchesTemplateLabels(bs.Selector, bs.ChannelTemplate) { - fe := apis.ErrInvalidValue(fmt.Sprint(bs.ChannelTemplate.metadata.Labels), "channelTemplate.metadata.labels") + fe := apis.ErrInvalidValue(fmt.Sprint(bs.ChannelTemplate.Metadata.Labels), "channelTemplate.metadata.labels") errs = errs.Also(fe) } @@ -60,7 +60,7 @@ func isSelectorNotPresentOrEmpty(s *v1.LabelSelector) bool { func selectorMatchesTemplateLabels(s *v1.LabelSelector, ct *ChannelTemplateSpec) bool { // TODO Improve this so it supports something other than direct label equality. - return equality.Semantic.DeepEqual(s.MatchLabels, ct.metadata.Labels) + return equality.Semantic.DeepEqual(s.MatchLabels, ct.Metadata.Labels) } func channelsInSubscribableResources(sr []v1.GroupVersionKind) bool { diff --git a/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go index 6481321c20e..8cbb1f99119 100644 --- a/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go @@ -291,7 +291,7 @@ func (in *ChannelStatus) DeepCopy() *ChannelStatus { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ChannelTemplateSpec) DeepCopyInto(out *ChannelTemplateSpec) { *out = *in - in.metadata.DeepCopyInto(&out.metadata) + in.Metadata.DeepCopyInto(&out.Metadata) if in.Spec != nil { in, out := &in.Spec, &out.Spec if *in == nil { From f20a2df95e4b66212fb671a55b0b92d56687853a Mon Sep 17 00:00:00 2001 From: Adam Harwayne Date: Mon, 28 Jan 2019 10:00:33 -0800 Subject: [PATCH 003/221] Initial Trigger API. --- .../eventing/v1alpha1/trigger_defaults.go | 27 +++ pkg/apis/eventing/v1alpha1/trigger_types.go | 138 ++++++++++++++ .../eventing/v1alpha1/trigger_validation.go | 88 +++++++++ .../v1alpha1/zz_generated.deepcopy.go | 148 +++++++++++++++ .../eventing/v1alpha1/eventing_client.go | 5 + .../v1alpha1/fake/fake_eventing_client.go | 4 + .../eventing/v1alpha1/fake/fake_trigger.go | 140 ++++++++++++++ .../eventing/v1alpha1/generated_expansion.go | 2 + .../typed/eventing/v1alpha1/trigger.go | 174 ++++++++++++++++++ .../eventing/v1alpha1/interface.go | 7 + .../eventing/v1alpha1/trigger.go | 89 +++++++++ .../informers/externalversions/generic.go | 2 + .../eventing/v1alpha1/expansion_generated.go | 8 + .../listers/eventing/v1alpha1/trigger.go | 94 ++++++++++ 14 files changed, 926 insertions(+) create mode 100644 pkg/apis/eventing/v1alpha1/trigger_defaults.go create mode 100644 pkg/apis/eventing/v1alpha1/trigger_types.go create mode 100644 pkg/apis/eventing/v1alpha1/trigger_validation.go create mode 100644 pkg/client/clientset/versioned/typed/eventing/v1alpha1/fake/fake_trigger.go create mode 100644 pkg/client/clientset/versioned/typed/eventing/v1alpha1/trigger.go create mode 100644 pkg/client/informers/externalversions/eventing/v1alpha1/trigger.go create mode 100644 pkg/client/listers/eventing/v1alpha1/trigger.go diff --git a/pkg/apis/eventing/v1alpha1/trigger_defaults.go b/pkg/apis/eventing/v1alpha1/trigger_defaults.go new file mode 100644 index 00000000000..732d9fde924 --- /dev/null +++ b/pkg/apis/eventing/v1alpha1/trigger_defaults.go @@ -0,0 +1,27 @@ +/* +Copyright 2019 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +func (t *Trigger) SetDefaults() { + t.Spec.SetDefaults() +} + +func (ts *TriggerSpec) SetDefaults() { + if ts.Broker == "" { + ts.Broker = "default" + } +} diff --git a/pkg/apis/eventing/v1alpha1/trigger_types.go b/pkg/apis/eventing/v1alpha1/trigger_types.go new file mode 100644 index 00000000000..8eecf20e6fc --- /dev/null +++ b/pkg/apis/eventing/v1alpha1/trigger_types.go @@ -0,0 +1,138 @@ +/* + * Copyright 2019 The Knative Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package v1alpha1 + +import ( + "github.com/knative/pkg/apis" + duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" + "github.com/knative/pkg/webhook" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// Trigger is an abstract resource that implements the Addressable contract. +// The Provisioner provisions infrastructure to accepts events and +// deliver to Subscriptions. +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"` +} + +// Check that Trigger can be validated, can be defaulted, and has immutable fields. +var _ apis.Validatable = (*Trigger)(nil) +var _ apis.Defaultable = (*Trigger)(nil) +var _ apis.Immutable = (*Trigger)(nil) +var _ runtime.Object = (*Trigger)(nil) +var _ webhook.GenericCRD = (*Trigger)(nil) + +// TriggerSpec specifies the Provisioner backing a channel and the configuration +// arguments for a Trigger. +type TriggerSpec struct { + Broker string `json:"broker,omitempty"` + Selector *TriggerSelectorSpec `json:"selector,omitempty"` + Subscriber *SubscriberSpec `json:"subscriber,omitempty"` +} + +type TriggerSelectorSpec struct { + Header map[string]string `json:"header,omitempty"` + HeaderExpression []metav1.LabelSelectorRequirement `json:"headerExpression,omitEmpty"` + OPAPolicy string `json:"opaPolicy,omitEmpty"` +} + +var triggerCondSet = duckv1alpha1.NewLivingConditionSet(TriggerConditionBrokerExists, TriggerConditionSubscriberFound) + +// TriggerStatus represents the current state of a Trigger. +type TriggerStatus struct { + // ObservedGeneration is the most recent generation observed for this Trigger. + // It corresponds to the Trigger's generation, which is updated on mutation by + // the API Server. + // TODO: The above comment is only true once + // https://github.com/kubernetes/kubernetes/issues/58778 is fixed. + // +optional + ObservedGeneration int64 `json:"observedGeneration,omitempty"` + + // Represents the latest available observations of a channel's current state. + // +optional + // +patchMergeKey=type + // +patchStrategy=merge + Conditions duckv1alpha1.Conditions `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"` +} + +const ( + // TriggerConditionReady has status True when the Trigger is ready to + // accept traffic. + TriggerConditionReady = duckv1alpha1.ConditionReady + + TriggerConditionBrokerExists duckv1alpha1.ConditionType = "BrokerExists" + + TriggerConditionSubscriberFound duckv1alpha1.ConditionType = "SubscriberFound" +) + +// GetCondition returns the condition currently associated with the given type, or nil. +func (ts *TriggerStatus) GetCondition(t duckv1alpha1.ConditionType) *duckv1alpha1.Condition { + return triggerCondSet.Manage(ts).GetCondition(t) +} + +// 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) MarkBrokerExists() { + triggerCondSet.Manage(ts).MarkTrue(TriggerConditionBrokerExists) +} + +func (ts *TriggerStatus) MarkBrokerDoesNotExists() { + triggerCondSet.Manage(ts).MarkFalse(TriggerConditionBrokerExists, "doesNotExist", "Broker does not exist") +} + +// MarkProvisioned sets TriggerConditionProvisioned condition to True state. +func (ts *TriggerStatus) MarkSubscriberFound() { + triggerCondSet.Manage(ts).MarkTrue(TriggerConditionSubscriberFound) +} + +// MarkNotProvisioned sets TriggerConditionProvisioned condition to False state. +func (ts *TriggerStatus) MarkSubscriberNotFound(reason, messageFormat string, messageA ...interface{}) { + triggerCondSet.Manage(ts).MarkFalse(TriggerConditionSubscriberFound, reason, messageFormat, messageA...) +} + +// +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"` +} diff --git a/pkg/apis/eventing/v1alpha1/trigger_validation.go b/pkg/apis/eventing/v1alpha1/trigger_validation.go new file mode 100644 index 00000000000..6ff7301e244 --- /dev/null +++ b/pkg/apis/eventing/v1alpha1/trigger_validation.go @@ -0,0 +1,88 @@ +/* +Copyright 2019 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + "github.com/google/go-cmp/cmp" + "github.com/knative/pkg/apis" + "k8s.io/apimachinery/pkg/api/equality" +) + +func (t *Trigger) Validate() *apis.FieldError { + return t.Spec.Validate().ViaField("spec") +} + +func (ts *TriggerSpec) Validate() *apis.FieldError { + var errs *apis.FieldError + if ts.Broker == "" { + fe := apis.ErrMissingField("broker") + errs = errs.Also(fe) + } + + if ts.Selector == nil { + fe := apis.ErrMissingField("selector") + errs = errs.Also(fe) + } else if fe := multipleSelectorsSet(ts.Selector); fe != nil { + errs = errs.Also(fe) + } + + if isSubscriberSpecNilOrEmpty(ts.Subscriber) { + fe := apis.ErrMissingField("subscriber") + errs = errs.Also(fe) + } else if fe := isValidSubscriberSpec(*ts.Subscriber); fe != nil { + errs = errs.Also(fe.ViaField("subscriber")) + } + + return errs +} + +func multipleSelectorsSet(s *TriggerSelectorSpec) *apis.FieldError { + var fields []string + if !equality.Semantic.DeepEqual(s.Header, map[string]string{}) { + fields = append(fields, "header") + } + if len(s.HeaderExpression) > 0 { + fields = append(fields, "headerExpression") + } + if s.OPAPolicy != "" { + fields = append(fields, "opaPolicy") + } + + if len(fields) != 1 { + return apis.ErrMultipleOneOf(fields...) + } + return nil +} + +func (t *Trigger) CheckImmutableFields(og apis.Immutable) *apis.FieldError { + original, ok := og.(*Trigger) + if !ok { + return &apis.FieldError{Message: "The provided original was not a Trigger"} + } + if original == nil { + return nil + } + + if diff := cmp.Diff(original.Spec.Broker, t.Spec.Broker); diff != "" { + return &apis.FieldError{ + Message: "Immutable fields changed (-old +new)", + Paths: []string{"spec", "broker"}, + Details: diff, + } + } + return nil +} diff --git a/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go index 8cbb1f99119..77046af1c1d 100644 --- a/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go @@ -608,3 +608,151 @@ func (in *SubscriptionStatusPhysicalSubscription) DeepCopy() *SubscriptionStatus in.DeepCopyInto(out) return out } + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *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 *TriggerList) DeepCopyInto(out *TriggerList) { + *out = *in + out.TypeMeta = in.TypeMeta + out.ListMeta = in.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 *TriggerSelectorSpec) DeepCopyInto(out *TriggerSelectorSpec) { + *out = *in + if in.Header != nil { + in, out := &in.Header, &out.Header + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.HeaderExpression != nil { + in, out := &in.HeaderExpression, &out.HeaderExpression + *out = make([]v1.LabelSelectorRequirement, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TriggerSelectorSpec. +func (in *TriggerSelectorSpec) DeepCopy() *TriggerSelectorSpec { + if in == nil { + return nil + } + out := new(TriggerSelectorSpec) + in.DeepCopyInto(out) + return out +} + +// 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.Selector != nil { + in, out := &in.Selector, &out.Selector + if *in == nil { + *out = nil + } else { + *out = new(TriggerSelectorSpec) + (*in).DeepCopyInto(*out) + } + } + if in.Subscriber != nil { + in, out := &in.Subscriber, &out.Subscriber + if *in == nil { + *out = nil + } else { + *out = new(SubscriberSpec) + (*in).DeepCopyInto(*out) + } + } + 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 + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make(duck_v1alpha1.Conditions, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + 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/typed/eventing/v1alpha1/eventing_client.go b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/eventing_client.go index 8a2796c7417..753d1081b84 100644 --- a/pkg/client/clientset/versioned/typed/eventing/v1alpha1/eventing_client.go +++ b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/eventing_client.go @@ -31,6 +31,7 @@ type EventingV1alpha1Interface interface { ChannelsGetter ClusterChannelProvisionersGetter SubscriptionsGetter + TriggersGetter } // EventingV1alpha1Client is used to interact with features provided by the eventing.knative.dev group. @@ -54,6 +55,10 @@ func (c *EventingV1alpha1Client) Subscriptions(namespace string) SubscriptionInt return newSubscriptions(c, namespace) } +func (c *EventingV1alpha1Client) Triggers(namespace string) TriggerInterface { + return newTriggers(c, namespace) +} + // NewForConfig creates a new EventingV1alpha1Client for the given config. func NewForConfig(c *rest.Config) (*EventingV1alpha1Client, error) { config := *c diff --git a/pkg/client/clientset/versioned/typed/eventing/v1alpha1/fake/fake_eventing_client.go b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/fake/fake_eventing_client.go index 68998cd28f5..4362e785f5a 100644 --- a/pkg/client/clientset/versioned/typed/eventing/v1alpha1/fake/fake_eventing_client.go +++ b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/fake/fake_eventing_client.go @@ -44,6 +44,10 @@ func (c *FakeEventingV1alpha1) Subscriptions(namespace string) v1alpha1.Subscrip return &FakeSubscriptions{c, namespace} } +func (c *FakeEventingV1alpha1) Triggers(namespace string) v1alpha1.TriggerInterface { + return &FakeTriggers{c, namespace} +} + // RESTClient returns a RESTClient that is used to communicate // with API server by this client implementation. func (c *FakeEventingV1alpha1) RESTClient() rest.Interface { diff --git a/pkg/client/clientset/versioned/typed/eventing/v1alpha1/fake/fake_trigger.go b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/fake/fake_trigger.go new file mode 100644 index 00000000000..5e4b588c6b1 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/fake/fake_trigger.go @@ -0,0 +1,140 @@ +/* +Copyright 2018 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT 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 ( + v1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" + 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" +) + +// FakeTriggers implements TriggerInterface +type FakeTriggers struct { + Fake *FakeEventingV1alpha1 + ns string +} + +var triggersResource = schema.GroupVersionResource{Group: "eventing.knative.dev", Version: "v1alpha1", Resource: "triggers"} + +var triggersKind = schema.GroupVersionKind{Group: "eventing.knative.dev", Version: "v1alpha1", 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 *v1alpha1.Trigger, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(triggersResource, c.ns, name), &v1alpha1.Trigger{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.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 *v1alpha1.TriggerList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(triggersResource, triggersKind, c.ns, opts), &v1alpha1.TriggerList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.TriggerList{ListMeta: obj.(*v1alpha1.TriggerList).ListMeta} + for _, item := range obj.(*v1alpha1.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 *v1alpha1.Trigger) (result *v1alpha1.Trigger, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(triggersResource, c.ns, trigger), &v1alpha1.Trigger{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.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 *v1alpha1.Trigger) (result *v1alpha1.Trigger, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(triggersResource, c.ns, trigger), &v1alpha1.Trigger{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.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 *v1alpha1.Trigger) (*v1alpha1.Trigger, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(triggersResource, "status", c.ns, trigger), &v1alpha1.Trigger{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.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), &v1alpha1.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, &v1alpha1.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 *v1alpha1.Trigger, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(triggersResource, c.ns, name, data, subresources...), &v1alpha1.Trigger{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.Trigger), err +} diff --git a/pkg/client/clientset/versioned/typed/eventing/v1alpha1/generated_expansion.go b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/generated_expansion.go index 94933cfbc74..2f88fb3320b 100644 --- a/pkg/client/clientset/versioned/typed/eventing/v1alpha1/generated_expansion.go +++ b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/generated_expansion.go @@ -25,3 +25,5 @@ type ChannelExpansion interface{} type ClusterChannelProvisionerExpansion interface{} type SubscriptionExpansion interface{} + +type TriggerExpansion interface{} diff --git a/pkg/client/clientset/versioned/typed/eventing/v1alpha1/trigger.go b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/trigger.go new file mode 100644 index 00000000000..72207e79d34 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/trigger.go @@ -0,0 +1,174 @@ +/* +Copyright 2018 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + v1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" + scheme "github.com/knative/eventing/pkg/client/clientset/versioned/scheme" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" +) + +// 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(*v1alpha1.Trigger) (*v1alpha1.Trigger, error) + Update(*v1alpha1.Trigger) (*v1alpha1.Trigger, error) + UpdateStatus(*v1alpha1.Trigger) (*v1alpha1.Trigger, error) + Delete(name string, options *v1.DeleteOptions) error + DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error + Get(name string, options v1.GetOptions) (*v1alpha1.Trigger, error) + List(opts v1.ListOptions) (*v1alpha1.TriggerList, error) + Watch(opts v1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.Trigger, err error) + TriggerExpansion +} + +// triggers implements TriggerInterface +type triggers struct { + client rest.Interface + ns string +} + +// newTriggers returns a Triggers +func newTriggers(c *EventingV1alpha1Client, 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 v1.GetOptions) (result *v1alpha1.Trigger, err error) { + result = &v1alpha1.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 v1.ListOptions) (result *v1alpha1.TriggerList, err error) { + result = &v1alpha1.TriggerList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("triggers"). + VersionedParams(&opts, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested triggers. +func (c *triggers) Watch(opts v1.ListOptions) (watch.Interface, error) { + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("triggers"). + VersionedParams(&opts, scheme.ParameterCodec). + 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 *v1alpha1.Trigger) (result *v1alpha1.Trigger, err error) { + result = &v1alpha1.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 *v1alpha1.Trigger) (result *v1alpha1.Trigger, err error) { + result = &v1alpha1.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 *v1alpha1.Trigger) (result *v1alpha1.Trigger, err error) { + result = &v1alpha1.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 *v1.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 *v1.DeleteOptions, listOptions v1.ListOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("triggers"). + VersionedParams(&listOptions, scheme.ParameterCodec). + 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 *v1alpha1.Trigger, err error) { + result = &v1alpha1.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/v1alpha1/interface.go b/pkg/client/informers/externalversions/eventing/v1alpha1/interface.go index 9d7b654e259..29ad6f191f0 100644 --- a/pkg/client/informers/externalversions/eventing/v1alpha1/interface.go +++ b/pkg/client/informers/externalversions/eventing/v1alpha1/interface.go @@ -32,6 +32,8 @@ type Interface interface { ClusterChannelProvisioners() ClusterChannelProvisionerInformer // Subscriptions returns a SubscriptionInformer. Subscriptions() SubscriptionInformer + // Triggers returns a TriggerInformer. + Triggers() TriggerInformer } type version struct { @@ -64,3 +66,8 @@ func (v *version) ClusterChannelProvisioners() ClusterChannelProvisionerInformer func (v *version) Subscriptions() SubscriptionInformer { return &subscriptionInformer{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/v1alpha1/trigger.go b/pkg/client/informers/externalversions/eventing/v1alpha1/trigger.go new file mode 100644 index 00000000000..c1b01ef002b --- /dev/null +++ b/pkg/client/informers/externalversions/eventing/v1alpha1/trigger.go @@ -0,0 +1,89 @@ +/* +Copyright 2018 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + time "time" + + eventing_v1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" + versioned "github.com/knative/eventing/pkg/client/clientset/versioned" + internalinterfaces "github.com/knative/eventing/pkg/client/informers/externalversions/internalinterfaces" + v1alpha1 "github.com/knative/eventing/pkg/client/listers/eventing/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" +) + +// TriggerInformer provides access to a shared informer and lister for +// Triggers. +type TriggerInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1alpha1.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 v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.EventingV1alpha1().Triggers(namespace).List(options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.EventingV1alpha1().Triggers(namespace).Watch(options) + }, + }, + &eventing_v1alpha1.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(&eventing_v1alpha1.Trigger{}, f.defaultInformer) +} + +func (f *triggerInformer) Lister() v1alpha1.TriggerLister { + return v1alpha1.NewTriggerLister(f.Informer().GetIndexer()) +} diff --git a/pkg/client/informers/externalversions/generic.go b/pkg/client/informers/externalversions/generic.go index 8e99e8692d4..6c22f720af9 100644 --- a/pkg/client/informers/externalversions/generic.go +++ b/pkg/client/informers/externalversions/generic.go @@ -61,6 +61,8 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource return &genericInformer{resource: resource.GroupResource(), informer: f.Eventing().V1alpha1().ClusterChannelProvisioners().Informer()}, nil case v1alpha1.SchemeGroupVersion.WithResource("subscriptions"): return &genericInformer{resource: resource.GroupResource(), informer: f.Eventing().V1alpha1().Subscriptions().Informer()}, nil + case v1alpha1.SchemeGroupVersion.WithResource("triggers"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Eventing().V1alpha1().Triggers().Informer()}, nil } diff --git a/pkg/client/listers/eventing/v1alpha1/expansion_generated.go b/pkg/client/listers/eventing/v1alpha1/expansion_generated.go index 2b4ca79dad1..2a49e1b434b 100644 --- a/pkg/client/listers/eventing/v1alpha1/expansion_generated.go +++ b/pkg/client/listers/eventing/v1alpha1/expansion_generated.go @@ -45,3 +45,11 @@ type SubscriptionListerExpansion interface{} // SubscriptionNamespaceListerExpansion allows custom methods to be added to // SubscriptionNamespaceLister. type SubscriptionNamespaceListerExpansion 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/v1alpha1/trigger.go b/pkg/client/listers/eventing/v1alpha1/trigger.go new file mode 100644 index 00000000000..56c323a8238 --- /dev/null +++ b/pkg/client/listers/eventing/v1alpha1/trigger.go @@ -0,0 +1,94 @@ +/* +Copyright 2018 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + v1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" +) + +// TriggerLister helps list Triggers. +type TriggerLister interface { + // List lists all Triggers in the indexer. + List(selector labels.Selector) (ret []*v1alpha1.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 []*v1alpha1.Trigger, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.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 []*v1alpha1.Trigger, err error) + // Get retrieves the Trigger from the indexer for a given namespace and name. + Get(name string) (*v1alpha1.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 []*v1alpha1.Trigger, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.Trigger)) + }) + return ret, err +} + +// Get retrieves the Trigger from the indexer for a given namespace and name. +func (s triggerNamespaceLister) Get(name string) (*v1alpha1.Trigger, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1alpha1.Resource("trigger"), name) + } + return obj.(*v1alpha1.Trigger), nil +} From 163474d1e414e44bfbeb29bb6c4a32a00232e123 Mon Sep 17 00:00:00 2001 From: Adam Harwayne Date: Mon, 28 Jan 2019 10:05:45 -0800 Subject: [PATCH 004/221] Remove old comments. --- pkg/apis/eventing/v1alpha1/broker_types.go | 11 +---------- pkg/apis/eventing/v1alpha1/trigger_types.go | 11 +---------- 2 files changed, 2 insertions(+), 20 deletions(-) diff --git a/pkg/apis/eventing/v1alpha1/broker_types.go b/pkg/apis/eventing/v1alpha1/broker_types.go index 08462a1fded..16a41df1c44 100644 --- a/pkg/apis/eventing/v1alpha1/broker_types.go +++ b/pkg/apis/eventing/v1alpha1/broker_types.go @@ -27,9 +27,6 @@ import ( // +genclient // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object -// Broker is an abstract resource that implements the Addressable contract. -// The Provisioner provisions infrastructure to accepts events and -// deliver to Subscriptions. type Broker struct { metav1.TypeMeta `json:",inline"` // +optional @@ -51,8 +48,6 @@ var _ apis.Immutable = (*Broker)(nil) var _ runtime.Object = (*Broker)(nil) var _ webhook.GenericCRD = (*Broker)(nil) -// BrokerSpec specifies the Provisioner backing a channel and the configuration -// arguments for a Broker. type BrokerSpec struct { Selector *metav1.LabelSelector `json:"selector,omitempty"` ChannelTemplate *ChannelTemplateSpec `json:"channelTemplate,omitempty"` @@ -76,7 +71,7 @@ type BrokerStatus struct { // +optional ObservedGeneration int64 `json:"observedGeneration,omitempty"` - // Represents the latest available observations of a channel's current state. + // Represents the latest available observations of a broker's current state. // +optional // +patchMergeKey=type // +patchStrategy=merge @@ -84,8 +79,6 @@ type BrokerStatus struct { } const ( - // BrokerConditionReady has status True when the Broker is ready to - // accept traffic. BrokerConditionReady = duckv1alpha1.ConditionReady BrokerConditionChannelTemplateSelector duckv1alpha1.ConditionType = "ChannelTemplateSelector" @@ -116,12 +109,10 @@ func (bs *BrokerStatus) MarkChannelTemplateDoesNotMatchSelector() { brokerCondSet.Manage(bs).MarkFalse(BrokerConditionChannelTemplateSelector, "selectorDoesNotMatchTemplate", "`spec.selector` does not match `spec.channelTempalte.meta.labels`") } -// MarkProvisioned sets BrokerConditionProvisioned condition to True state. func (bs *BrokerStatus) MarkSubscribableResourcesExist() { brokerCondSet.Manage(bs).MarkTrue(BrokerConditionSubscribableResourcesExist) } -// MarkNotProvisioned sets BrokerConditionProvisioned condition to False state. func (bs *BrokerStatus) MarkSubscribableResourcesDoNotExist(reason, messageFormat string, messageA ...interface{}) { brokerCondSet.Manage(bs).MarkFalse(BrokerConditionSubscribableResourcesExist, reason, messageFormat, messageA...) } diff --git a/pkg/apis/eventing/v1alpha1/trigger_types.go b/pkg/apis/eventing/v1alpha1/trigger_types.go index 8eecf20e6fc..82ac3aa648f 100644 --- a/pkg/apis/eventing/v1alpha1/trigger_types.go +++ b/pkg/apis/eventing/v1alpha1/trigger_types.go @@ -27,9 +27,6 @@ import ( // +genclient // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object -// Trigger is an abstract resource that implements the Addressable contract. -// The Provisioner provisions infrastructure to accepts events and -// deliver to Subscriptions. type Trigger struct { metav1.TypeMeta `json:",inline"` // +optional @@ -51,8 +48,6 @@ var _ apis.Immutable = (*Trigger)(nil) var _ runtime.Object = (*Trigger)(nil) var _ webhook.GenericCRD = (*Trigger)(nil) -// TriggerSpec specifies the Provisioner backing a channel and the configuration -// arguments for a Trigger. type TriggerSpec struct { Broker string `json:"broker,omitempty"` Selector *TriggerSelectorSpec `json:"selector,omitempty"` @@ -77,7 +72,7 @@ type TriggerStatus struct { // +optional ObservedGeneration int64 `json:"observedGeneration,omitempty"` - // Represents the latest available observations of a channel's current state. + // Represents the latest available observations of a trigger's current state. // +optional // +patchMergeKey=type // +patchStrategy=merge @@ -85,8 +80,6 @@ type TriggerStatus struct { } const ( - // TriggerConditionReady has status True when the Trigger is ready to - // accept traffic. TriggerConditionReady = duckv1alpha1.ConditionReady TriggerConditionBrokerExists duckv1alpha1.ConditionType = "BrokerExists" @@ -117,12 +110,10 @@ func (ts *TriggerStatus) MarkBrokerDoesNotExists() { triggerCondSet.Manage(ts).MarkFalse(TriggerConditionBrokerExists, "doesNotExist", "Broker does not exist") } -// MarkProvisioned sets TriggerConditionProvisioned condition to True state. func (ts *TriggerStatus) MarkSubscriberFound() { triggerCondSet.Manage(ts).MarkTrue(TriggerConditionSubscriberFound) } -// MarkNotProvisioned sets TriggerConditionProvisioned condition to False state. func (ts *TriggerStatus) MarkSubscriberNotFound(reason, messageFormat string, messageA ...interface{}) { triggerCondSet.Manage(ts).MarkFalse(TriggerConditionSubscriberFound, reason, messageFormat, messageA...) } From 5f53e05385bf1450eb33453369973a49ad05f7df Mon Sep 17 00:00:00 2001 From: Adam Harwayne Date: Mon, 28 Jan 2019 10:12:25 -0800 Subject: [PATCH 005/221] Register the types. --- cmd/webhook/main.go | 2 ++ config/300-broker.yaml | 38 ++++++++++++++++++++++++++ config/300-trigger.yaml | 38 ++++++++++++++++++++++++++ pkg/apis/eventing/v1alpha1/register.go | 4 +++ 4 files changed, 82 insertions(+) create mode 100644 config/300-broker.yaml create mode 100644 config/300-trigger.yaml diff --git a/cmd/webhook/main.go b/cmd/webhook/main.go index e35ff3d7304..400a452cd9a 100644 --- a/cmd/webhook/main.go +++ b/cmd/webhook/main.go @@ -96,9 +96,11 @@ func main() { Options: options, Handlers: map[schema.GroupVersionKind]webhook.GenericCRD{ // For group eventing.knative.dev, + eventingv1alpha1.SchemeGroupVersion.WithKind("Broker"): &eventingv1alpha1.Broker{}, eventingv1alpha1.SchemeGroupVersion.WithKind("Channel"): &eventingv1alpha1.Channel{}, eventingv1alpha1.SchemeGroupVersion.WithKind("ClusterChannelProvisioner"): &eventingv1alpha1.ClusterChannelProvisioner{}, eventingv1alpha1.SchemeGroupVersion.WithKind("Subscription"): &eventingv1alpha1.Subscription{}, + eventingv1alpha1.SchemeGroupVersion.WithKind("Trigger"): &eventingv1alpha1.Trigger{}, }, Logger: logger, } diff --git a/config/300-broker.yaml b/config/300-broker.yaml new file mode 100644 index 00000000000..ce0421a7b66 --- /dev/null +++ b/config/300-broker.yaml @@ -0,0 +1,38 @@ +# Copyright 2019 The Knative Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: brokers.eventing.knative.dev +spec: + group: eventing.knative.dev + version: v1alpha1 + names: + kind: Broker + plural: brokers + singular: broker + categories: + - all + - knative + - eventing + scope: Namespaced + subresources: + status: {} + additionalPrinterColumns: + - name: Ready + type: string + JSONPath: ".status.conditions[?(@.type==\"Ready\")].status" + - name: Reason + type: string + JSONPath: ".status.conditions[?(@.type==\"Ready\")].reason" diff --git a/config/300-trigger.yaml b/config/300-trigger.yaml new file mode 100644 index 00000000000..5ca0c8beb24 --- /dev/null +++ b/config/300-trigger.yaml @@ -0,0 +1,38 @@ +# Copyright 2019 The Knative Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: triggers.eventing.knative.dev +spec: + group: eventing.knative.dev + version: v1alpha1 + names: + kind: Trigger + plural: triggers + singular: trigger + categories: + - all + - knative + - eventing + scope: Namespaced + subresources: + status: {} + additionalPrinterColumns: + - name: Ready + type: string + JSONPath: ".status.conditions[?(@.type==\"Ready\")].status" + - name: Reason + type: string + JSONPath: ".status.conditions[?(@.type==\"Ready\")].reason" diff --git a/pkg/apis/eventing/v1alpha1/register.go b/pkg/apis/eventing/v1alpha1/register.go index df6338f66c1..fb3a5292623 100644 --- a/pkg/apis/eventing/v1alpha1/register.go +++ b/pkg/apis/eventing/v1alpha1/register.go @@ -45,12 +45,16 @@ var ( // Adds the list of known types to Scheme. func addKnownTypes(scheme *runtime.Scheme) error { scheme.AddKnownTypes(SchemeGroupVersion, + &Broker{}, + &BrokerList{}, &Channel{}, &ChannelList{}, &ClusterChannelProvisioner{}, &ClusterChannelProvisionerList{}, &Subscription{}, &SubscriptionList{}, + &Trigger{}, + &TriggerList{}, ) metav1.AddToGroupVersion(scheme, SchemeGroupVersion) return nil From 2f6a03f7ab3c8192367a1ae8f0c7c70eadd1f606 Mon Sep 17 00:00:00 2001 From: Adam Harwayne Date: Mon, 28 Jan 2019 15:33:47 -0800 Subject: [PATCH 006/221] Initial work on the Broker controller. --- cmd/controller/main.go | 3 + pkg/apis/eventing/v1alpha1/broker_types.go | 32 +- pkg/controller/eventing/broker/provider.go | 89 ++++ pkg/controller/eventing/broker/reconcile.go | 419 ++++++++++++++++++ .../eventing/broker/resources/activator.go | 75 ++++ .../eventing/broker/resources/router.go | 80 ++++ 6 files changed, 695 insertions(+), 3 deletions(-) create mode 100644 pkg/controller/eventing/broker/provider.go create mode 100644 pkg/controller/eventing/broker/reconcile.go create mode 100644 pkg/controller/eventing/broker/resources/activator.go create mode 100644 pkg/controller/eventing/broker/resources/router.go diff --git a/cmd/controller/main.go b/cmd/controller/main.go index be41cfc443a..ea76ced13c4 100644 --- a/cmd/controller/main.go +++ b/cmd/controller/main.go @@ -23,6 +23,8 @@ import ( "net/http" "time" + "github.com/knative/eventing/pkg/controller/eventing/broker" + "github.com/knative/eventing/pkg/controller/eventing/subscription" "k8s.io/apimachinery/pkg/runtime" "sigs.k8s.io/controller-runtime/pkg/controller" @@ -119,6 +121,7 @@ func main() { // manager run it. providers := []ProvideFunc{ subscription.ProvideController, + broker.ProvideController(logger.Desugar()), } for _, provider := range providers { if _, err := provider(mgr); err != nil { diff --git a/pkg/apis/eventing/v1alpha1/broker_types.go b/pkg/apis/eventing/v1alpha1/broker_types.go index 16a41df1c44..20a6a945c3f 100644 --- a/pkg/apis/eventing/v1alpha1/broker_types.go +++ b/pkg/apis/eventing/v1alpha1/broker_types.go @@ -59,7 +59,7 @@ type ChannelTemplateSpec struct { Spec *ChannelSpec `json:"spec,omitempty"` } -var brokerCondSet = duckv1alpha1.NewLivingConditionSet(BrokerConditionChannelTemplateSelector, BrokerConditionSubscribableResourcesExist) +var brokerCondSet = duckv1alpha1.NewLivingConditionSet(BrokerConditionChannelTemplateSelector, BrokerConditionSubscribableResourcesExist, BrokerConditionSubscribableResourcesExist, BrokerConditionAddressable) // BrokerStatus represents the current state of a Broker. type BrokerStatus struct { @@ -76,6 +76,13 @@ type BrokerStatus struct { // +patchMergeKey=type // +patchStrategy=merge Conditions duckv1alpha1.Conditions `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"` + + // Broker is Addressable. It currently exposes the endpoint as a + // fully-qualified DNS name which will distribute traffic over the + // provided targets from inside the cluster. + // + // It generally has the form {broker}-router.{namespace}.svc.{cluster domain name} + Address duckv1alpha1.Addressable `json:"address,omitempty"` } const ( @@ -84,6 +91,10 @@ const ( BrokerConditionChannelTemplateSelector duckv1alpha1.ConditionType = "ChannelTemplateSelector" BrokerConditionSubscribableResourcesExist duckv1alpha1.ConditionType = "SubscribableResourcesExist" + + BrokerConditionRouterAndActivatorExist duckv1alpha1.ConditionType = "RouterAndActivatorCreated" + + BrokerConditionAddressable duckv1alpha1.ConditionType = "Addressable" ) // GetCondition returns the condition currently associated with the given type, or nil. @@ -113,8 +124,23 @@ func (bs *BrokerStatus) MarkSubscribableResourcesExist() { brokerCondSet.Manage(bs).MarkTrue(BrokerConditionSubscribableResourcesExist) } -func (bs *BrokerStatus) MarkSubscribableResourcesDoNotExist(reason, messageFormat string, messageA ...interface{}) { - brokerCondSet.Manage(bs).MarkFalse(BrokerConditionSubscribableResourcesExist, reason, messageFormat, messageA...) +func (bs *BrokerStatus) MarkSubscribableResourcesDoNotExist(dontExist []metav1.GroupVersionKind) { + brokerCondSet.Manage(bs).MarkFalse(BrokerConditionSubscribableResourcesExist, "resourcesDontExist", "The following resources do not exist: %v", dontExist) +} + +func (bs *BrokerStatus) MarkRouterAndActivatorExist() { + brokerCondSet.Manage(bs).MarkTrue(BrokerConditionRouterAndActivatorExist) +} + +// SetAddress makes this Channel addressable by setting the hostname. It also +// sets the ChannelConditionAddressable to true. +func (bs *BrokerStatus) SetAddress(hostname string) { + bs.Address.Hostname = hostname + if hostname != "" { + chanCondSet.Manage(bs).MarkTrue(BrokerConditionAddressable) + } else { + chanCondSet.Manage(bs).MarkFalse(BrokerConditionAddressable, "emptyHostname", "hostname is the empty string") + } } // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object diff --git a/pkg/controller/eventing/broker/provider.go b/pkg/controller/eventing/broker/provider.go new file mode 100644 index 00000000000..9315366245c --- /dev/null +++ b/pkg/controller/eventing/broker/provider.go @@ -0,0 +1,89 @@ +/* +Copyright 2018 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT 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 broker + +import ( + "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" + "go.uber.org/zap" + "k8s.io/client-go/dynamic" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/record" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller" + "sigs.k8s.io/controller-runtime/pkg/handler" + "sigs.k8s.io/controller-runtime/pkg/manager" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + "sigs.k8s.io/controller-runtime/pkg/source" +) + +const ( + // controllerAgentName is the string used by this controller to identify + // itself when creating events. + controllerAgentName = "broker-controller" +) + +type reconciler struct { + client client.Client + restConfig *rest.Config + dynamicClient dynamic.Interface + recorder record.EventRecorder + + logger *zap.Logger + + routerImage string + routerServiceAccountName string + activatorImage string + activatorServiceAccountName string +} + +// Verify the struct implements reconcile.Reconciler +var _ reconcile.Reconciler = &reconciler{} + +// ProvideController returns a function that returns a Broker controller. +func ProvideController(logger *zap.Logger) func(manager.Manager) (controller.Controller, error) { + return func(mgr manager.Manager) (controller.Controller, error) { + // Setup a new controller to Reconcile Brokers. + c, err := controller.New(controllerAgentName, mgr, controller.Options{ + Reconciler: &reconciler{ + recorder: mgr.GetRecorder(controllerAgentName), + logger: logger, + }, + }) + if err != nil { + return nil, err + } + + // Watch Subscription events and enqueue Subscription object key. + if err = c.Watch(&source.Kind{Type: &v1alpha1.Broker{}}, &handler.EnqueueRequestForObject{}); err != nil { + return nil, err + } + + return c, nil + } +} + +func (r *reconciler) InjectClient(c client.Client) error { + r.client = c + return nil +} + +func (r *reconciler) InjectConfig(c *rest.Config) error { + r.restConfig = c + var err error + r.dynamicClient, err = dynamic.NewForConfig(c) + return err +} diff --git a/pkg/controller/eventing/broker/reconcile.go b/pkg/controller/eventing/broker/reconcile.go new file mode 100644 index 00000000000..e46d4b263d1 --- /dev/null +++ b/pkg/controller/eventing/broker/reconcile.go @@ -0,0 +1,419 @@ +/* +Copyright 2018 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT 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 broker + +import ( + "context" + "fmt" + + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/runtime/schema" + + "github.com/knative/eventing/pkg/controller/eventing/broker/resources" + + servingv1alpha1 "github.com/knative/serving/pkg/apis/serving/v1alpha1" + + "github.com/knative/eventing/pkg/provisioners/gcppubsub/util/logging" + "go.uber.org/zap" + + "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/equality" + "k8s.io/apimachinery/pkg/api/errors" + k8serrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + runtimeclient "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/reconcile" +) + +const ( + // Name of the corev1.Events emitted from the reconciliation process + brokerReconciled = "BrokerReconciled" + brokerUpdateStatusFailed = "BrokerUpdateStatusFailed" +) + +// Reconcile compares the actual state with the desired, and attempts to +// converge the two. It then updates the Status block of the Broker resource +// with the current status of the resource. +func (r *reconciler) Reconcile(request reconcile.Request) (reconcile.Result, error) { + ctx := context.TODO() + ctx = logging.WithLogger(ctx, r.logger.With(zap.Any("request", request))) + + broker := &v1alpha1.Broker{} + err := r.client.Get(context.TODO(), request.NamespacedName, broker) + + if errors.IsNotFound(err) { + logging.FromContext(ctx).Info("Could not find Broker") + return reconcile.Result{}, nil + } + + if err != nil { + logging.FromContext(ctx).Error("Could not Get Broker", zap.Error(err)) + return reconcile.Result{}, err + } + + // Reconcile this copy of the Broker and then write back any status updates regardless of + // whether the reconcile error out. + reconcileErr := r.reconcile(ctx, broker) + if reconcileErr != nil { + logging.FromContext(ctx).Error("Error reconciling Broker", zap.Error(reconcileErr)) + } else { + logging.FromContext(ctx).Debug("Broker reconciled") + r.recorder.Event(broker, corev1.EventTypeNormal, brokerReconciled, "Broker reconciled") + } + + if _, err := r.updateStatus(broker.DeepCopy()); err != nil { + logging.FromContext(ctx).Error("Failed to update Broker status", zap.Error(err)) + r.recorder.Eventf(broker, corev1.EventTypeWarning, brokerUpdateStatusFailed, "Failed to update Broker's status: %v", err) + return reconcile.Result{}, err + } + + // Requeue if the resource is not ready: + return reconcile.Result{}, err +} + +func (r *reconciler) reconcile(ctx context.Context, b *v1alpha1.Broker) error { + b.Status.InitializeConditions() + + // 1. Create the router. + // 2. Create the activator. + // 3. Create the filter [do not do for the prototype]. + // 4. Create the 'needs-activation' Channel. + // 5. Create Subscription from 'needs-activation' Channel to the activator. + + if b.DeletionTimestamp != nil { + // Everything is cleaned up by the garbage collector. + return nil + } + + // TODO Actually check this, for now the webhook ensures they are identical. + b.Status.MarkChannelTemplateMatchesSelector() + + dontExist, err := r.verifyResourcesExist(ctx, b.Spec.SubscribableResources) + if err != nil { + logging.FromContext(ctx).Error("Unable to determine if resources exist", zap.Error(err)) + return err + } else if len(dontExist) > 0 { + b.Status.MarkSubscribableResourcesDoNotExist(dontExist) + } else { + b.Status.MarkSubscribableResourcesExist() + } + + activator, err := r.reconcileActivator(ctx, b) + if err != nil { + logging.FromContext(ctx).Error("Problem reconciling activator", zap.Error(err)) + return err + } + + // TODO Add the filter reconciliation here. + + c, err := r.reconcileNeedsActivationChannel(ctx, b) + if err != nil { + logging.FromContext(ctx).Error("Problem reconciling the needs activation channel", zap.Error(err)) + return err + } + + _, err = r.reconcileNeedsActivationSubscription(ctx, b, activator, c) + if err != nil { + logging.FromContext(ctx).Error("Problem reconciling the needs activation subscription", zap.Error(err)) + return err + } + b.Status.MarkRouterAndActivatorExist() + + router, err := r.reconcileRouter(ctx, b, c) + if err != nil { + logging.FromContext(ctx).Error("Problem reconciling router", zap.Error(err)) + return err + } + b.Status.SetAddress(router.Status.Address.Hostname) + + return nil +} + +// updateStatus may in fact update the broker's finalizers in addition to the status +func (r *reconciler) updateStatus(broker *v1alpha1.Broker) (*v1alpha1.Broker, error) { + objectKey := client.ObjectKey{Namespace: broker.Namespace, Name: broker.Name} + latestBroker := &v1alpha1.Broker{} + + if err := r.client.Get(context.TODO(), objectKey, latestBroker); err != nil { + return nil, err + } + + brokerChanged := false + + if !equality.Semantic.DeepEqual(latestBroker.Finalizers, broker.Finalizers) { + latestBroker.SetFinalizers(broker.ObjectMeta.Finalizers) + if err := r.client.Update(context.TODO(), latestBroker); err != nil { + return nil, err + } + brokerChanged = true + } + + if equality.Semantic.DeepEqual(latestBroker.Status, broker.Status) { + return latestBroker, nil + } + + if brokerChanged { + // Refetch + latestBroker = &v1alpha1.Broker{} + if err := r.client.Get(context.TODO(), objectKey, latestBroker); err != nil { + return nil, err + } + } + + latestBroker.Status = broker.Status + if err := r.client.Status().Update(context.TODO(), latestBroker); err != nil { + return nil, err + } + + return latestBroker, nil +} + +func (r *reconciler) verifyResourcesExist(ctx context.Context, resources []metav1.GroupVersionKind) ([]metav1.GroupVersionKind, error) { + dontExist := make([]metav1.GroupVersionKind, 0, len(resources)) + // TODO Implement, for now the webhook asserts it is only Channel, which we assume exists. + return dontExist, nil +} + +func (r *reconciler) reconcileActivator(ctx context.Context, b *v1alpha1.Broker) (*servingv1alpha1.Service, error) { + expected, err := resources.MakeActivator(&resources.ActivatorArgs{ + Broker: b, + Image: r.activatorImage, + ServiceAccountName: r.activatorServiceAccountName, + }) + if err != nil { + return nil, err + } + return r.reconcileKSvc(ctx, expected) +} + +func (r *reconciler) reconcileNeedsActivationChannel(ctx context.Context, b *v1alpha1.Broker) (*v1alpha1.Channel, error) { + expected := newNeedsActivationChannel(b) + + c, err := r.getNeedsActivationChannel(ctx, b) + // If the resource doesn't exist, we'll create it + if k8serrors.IsNotFound(err) { + c = expected + err = r.client.Create(ctx, c) + if err != nil { + return nil, err + } + return c, nil + } else if err != nil { + return nil, err + } + + // Update Channel if it has changed. Note that we need to both ignore the real Channel's + // subscribable section and if we need to update the real Channel, retain it. + expected.Spec.Subscribable = c.Spec.Subscribable + if !equality.Semantic.DeepDerivative(expected.Spec, c.Spec) { + c.Spec = expected.Spec + err = r.client.Update(ctx, c) + if err != nil { + return nil, err + } + } + return c, nil +} + +func (r *reconciler) getNeedsActivationChannel(ctx context.Context, b *v1alpha1.Broker) (*v1alpha1.Channel, error) { + list := &v1alpha1.ChannelList{} + opts := &runtimeclient.ListOptions{ + Namespace: b.Namespace, + LabelSelector: labels.SelectorFromSet(needsActivationLabels(b)), + // TODO this is here because the fake client needs it. Remove this when it's no longer + // needed. + Raw: &metav1.ListOptions{ + TypeMeta: metav1.TypeMeta{ + APIVersion: v1alpha1.SchemeGroupVersion.String(), + Kind: "Channel", + }, + }, + } + + err := r.client.List(ctx, opts, list) + if err != nil { + return nil, err + } + for _, c := range list.Items { + if metav1.IsControlledBy(&c, b) { + return &c, nil + } + } + + return nil, k8serrors.NewNotFound(schema.GroupResource{}, "") +} + +func newNeedsActivationChannel(b *v1alpha1.Broker) *v1alpha1.Channel { + var spec v1alpha1.ChannelSpec + if b.Spec.ChannelTemplate != nil && b.Spec.ChannelTemplate.Spec != nil { + spec = *b.Spec.ChannelTemplate.Spec + } + + return &v1alpha1.Channel{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: b.Namespace, + GenerateName: fmt.Sprintf("%s-broker-needs-activation-", b.Name), + OwnerReferences: []metav1.OwnerReference{ + *metav1.NewControllerRef(b, schema.GroupVersionKind{ + Group: b.GroupVersionKind().Group, + Version: b.GroupVersionKind().Version, + Kind: b.GroupVersionKind().Kind, + }), + }, + }, + Spec: spec, + } +} + +func needsActivationLabels(b *v1alpha1.Broker) map[string]string { + return map[string]string{ + "eventing.knative.dev/broker": b.Name, + "eventing.knative.dev/broker/needsActivation": "true", + } +} + +func (r *reconciler) reconcileNeedsActivationSubscription(ctx context.Context, b *v1alpha1.Broker, activator *servingv1alpha1.Service, c *v1alpha1.Channel) (*v1alpha1.Subscription, error) { + expected := newNeedsActivationSubscription(b, c, activator) + + sub, err := r.getNeedsActivationSubscription(ctx, b) + // If the resource doesn't exist, we'll create it + if k8serrors.IsNotFound(err) { + sub = expected + err = r.client.Create(ctx, sub) + if err != nil { + return nil, err + } + return sub, nil + } else if err != nil { + return nil, err + } + + // Update Subscription if it has changed. + if !equality.Semantic.DeepDerivative(expected.Spec, sub.Spec) { + sub.Spec = expected.Spec + err = r.client.Update(ctx, sub) + if err != nil { + return nil, err + } + } + return sub, nil +} + +func (r *reconciler) getNeedsActivationSubscription(ctx context.Context, b *v1alpha1.Broker) (*v1alpha1.Subscription, error) { + list := &v1alpha1.SubscriptionList{} + opts := &runtimeclient.ListOptions{ + Namespace: b.Namespace, + LabelSelector: labels.SelectorFromSet(needsActivationLabels(b)), + // TODO this is here because the fake client needs it. Remove this when it's no longer + // needed. + Raw: &metav1.ListOptions{ + TypeMeta: metav1.TypeMeta{ + APIVersion: v1alpha1.SchemeGroupVersion.String(), + Kind: "Subscription", + }, + }, + } + + err := r.client.List(ctx, opts, list) + if err != nil { + return nil, err + } + for _, sub := range list.Items { + if metav1.IsControlledBy(&sub, b) { + return &sub, nil + } + } + + return nil, k8serrors.NewNotFound(schema.GroupResource{}, "") +} + +func newNeedsActivationSubscription(b *v1alpha1.Broker, c *v1alpha1.Channel, activator *servingv1alpha1.Service) *v1alpha1.Subscription { + return &v1alpha1.Subscription{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: b.Namespace, + GenerateName: fmt.Sprintf("%s-broker-needs-activation-", b.Name), + OwnerReferences: []metav1.OwnerReference{ + *metav1.NewControllerRef(b, schema.GroupVersionKind{ + Group: b.GroupVersionKind().Group, + Version: b.GroupVersionKind().Version, + Kind: b.GroupVersionKind().Kind, + }), + }, + }, + Spec: v1alpha1.SubscriptionSpec{ + Channel: corev1.ObjectReference{ + APIVersion: c.APIVersion, + Kind: c.Kind, + Namespace: c.Namespace, + Name: c.Name, + UID: c.UID, + }, + Subscriber: &v1alpha1.SubscriberSpec{ + Ref: &corev1.ObjectReference{ + APIVersion: activator.APIVersion, + Kind: activator.Kind, + Namespace: activator.Namespace, + Name: activator.Name, + UID: activator.UID, + }, + }, + }, + } +} + +func (r *reconciler) reconcileKSvc(ctx context.Context, ksvc *servingv1alpha1.Service) (*servingv1alpha1.Service, error) { + name := types.NamespacedName{ + Namespace: ksvc.Namespace, + Name: ksvc.Name, + } + current := &servingv1alpha1.Service{} + err := r.client.Get(ctx, name, current) + if k8serrors.IsNotFound(err) { + err = r.client.Create(ctx, ksvc) + if err != nil { + return nil, err + } + return ksvc, nil + } else if err != nil { + return nil, err + } + + if !equality.Semantic.DeepDerivative(ksvc.Spec, current.Spec) { + current.Spec = ksvc.Spec + err = r.client.Update(ctx, current) + if err != nil { + return nil, err + } + } + return current, nil +} + +func (r *reconciler) reconcileRouter(ctx context.Context, b *v1alpha1.Broker, c *v1alpha1.Channel) (*servingv1alpha1.Service, error) { + expected, err := resources.MakeRouter(&resources.RouterArgs{ + Broker: b, + Image: r.routerImage, + ServiceAccountName: r.routerServiceAccountName, + NeedsActivationHost: c.Status.Address.Hostname, + }) + if err != nil { + return nil, err + } + return r.reconcileKSvc(ctx, expected) +} diff --git a/pkg/controller/eventing/broker/resources/activator.go b/pkg/controller/eventing/broker/resources/activator.go new file mode 100644 index 00000000000..1de0820eef1 --- /dev/null +++ b/pkg/controller/eventing/broker/resources/activator.go @@ -0,0 +1,75 @@ +/* +Copyright 2018 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT 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 resources + +import ( + "encoding/json" + "fmt" + + eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" + servingv1alpha1 "github.com/knative/serving/pkg/apis/serving/v1alpha1" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +type ActivatorArgs struct { + Broker *eventingv1alpha1.Broker + Image string + ServiceAccountName string +} + +func MakeActivator(args *ActivatorArgs) (*servingv1alpha1.Service, error) { + templateJson, err := json.Marshal(args.Broker.Spec.ChannelTemplate) + if err != nil { + return nil, err + } + + return &servingv1alpha1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: args.Broker.Namespace, + Name: fmt.Sprintf("%s-broker-activator", args.Broker.Name), + OwnerReferences: []metav1.OwnerReference{ + *metav1.NewControllerRef(args.Broker, schema.GroupVersionKind{ + Group: args.Broker.GroupVersionKind().Group, + Version: args.Broker.GroupVersionKind().Version, + Kind: args.Broker.GroupVersionKind().Kind, + }), + }, + }, + Spec: servingv1alpha1.ServiceSpec{ + RunLatest: &servingv1alpha1.RunLatestType{ + Configuration: servingv1alpha1.ConfigurationSpec{ + RevisionTemplate: servingv1alpha1.RevisionTemplateSpec{ + Spec: servingv1alpha1.RevisionSpec{ + ServiceAccountName: args.ServiceAccountName, + Container: v1.Container{ + Image: args.Image, + Env: []v1.EnvVar{ + { + Name: "CHANNEL_TEMPLATE", + Value: string(templateJson), + }, + }, + }, + }, + }, + }, + }, + }, + }, nil +} diff --git a/pkg/controller/eventing/broker/resources/router.go b/pkg/controller/eventing/broker/resources/router.go new file mode 100644 index 00000000000..baf8ac4b39c --- /dev/null +++ b/pkg/controller/eventing/broker/resources/router.go @@ -0,0 +1,80 @@ +/* +Copyright 2018 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT 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 resources + +import ( + "encoding/json" + "fmt" + + eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" + servingv1alpha1 "github.com/knative/serving/pkg/apis/serving/v1alpha1" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +type RouterArgs struct { + Broker *eventingv1alpha1.Broker + Image string + ServiceAccountName string + NeedsActivationHost string +} + +func MakeRouter(args *RouterArgs) (*servingv1alpha1.Service, error) { + selectorJson, err := json.Marshal(args.Broker.Spec.Selector) + if err != nil { + return nil, err + } + + return &servingv1alpha1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: args.Broker.Namespace, + Name: fmt.Sprintf("%s-broker", args.Broker.Name), + OwnerReferences: []metav1.OwnerReference{ + *metav1.NewControllerRef(args.Broker, schema.GroupVersionKind{ + Group: args.Broker.GroupVersionKind().Group, + Version: args.Broker.GroupVersionKind().Version, + Kind: args.Broker.GroupVersionKind().Kind, + }), + }, + }, + Spec: servingv1alpha1.ServiceSpec{ + RunLatest: &servingv1alpha1.RunLatestType{ + Configuration: servingv1alpha1.ConfigurationSpec{ + RevisionTemplate: servingv1alpha1.RevisionTemplateSpec{ + Spec: servingv1alpha1.RevisionSpec{ + ServiceAccountName: args.ServiceAccountName, + Container: v1.Container{ + Image: args.Image, + Env: []v1.EnvVar{ + { + Name: "NEEDS_ACTIVATION_HOST", + Value: args.NeedsActivationHost, + }, + { + Name: "LABEL_SELECTOR", + Value: string(selectorJson), + }, + }, + }, + }, + }, + }, + }, + }, + }, nil +} From 3ee0b8b6573e7a36ba757ae534e45a07d13371e2 Mon Sep 17 00:00:00 2001 From: Adam Harwayne Date: Thu, 31 Jan 2019 13:54:59 -0800 Subject: [PATCH 007/221] Initial work on the Trigger controller. --- cmd/controller/main.go | 5 +- pkg/apis/eventing/v1alpha1/trigger_types.go | 15 +- pkg/controller/eventing/broker/reconcile.go | 2 +- pkg/controller/eventing/trigger/provider.go | 113 ++++++ pkg/controller/eventing/trigger/reconcile.go | 366 ++++++++++++++++++ .../eventing/trigger/resources/activator.go | 75 ++++ .../eventing/trigger/resources/router.go | 80 ++++ pkg/provisioners/channel_util.go | 14 +- 8 files changed, 655 insertions(+), 15 deletions(-) create mode 100644 pkg/controller/eventing/trigger/provider.go create mode 100644 pkg/controller/eventing/trigger/reconcile.go create mode 100644 pkg/controller/eventing/trigger/resources/activator.go create mode 100644 pkg/controller/eventing/trigger/resources/router.go diff --git a/cmd/controller/main.go b/cmd/controller/main.go index ea76ced13c4..22212fc6e6c 100644 --- a/cmd/controller/main.go +++ b/cmd/controller/main.go @@ -23,6 +23,8 @@ import ( "net/http" "time" + "github.com/knative/eventing/pkg/controller/eventing/trigger" + "github.com/knative/eventing/pkg/controller/eventing/broker" "github.com/knative/eventing/pkg/controller/eventing/subscription" @@ -112,7 +114,7 @@ func main() { eventingv1alpha1.AddToScheme, } for _, schemeFunc := range schemeFuncs { - if err := schemeFunc(mgr.GetScheme()); err != nil { + if err = schemeFunc(mgr.GetScheme()); err != nil { logger.Fatalf("Error adding type to manager's scheme: %v", err) } } @@ -122,6 +124,7 @@ func main() { providers := []ProvideFunc{ subscription.ProvideController, broker.ProvideController(logger.Desugar()), + trigger.ProvideController(logger.Desugar()), } for _, provider := range providers { if _, err := provider(mgr); err != nil { diff --git a/pkg/apis/eventing/v1alpha1/trigger_types.go b/pkg/apis/eventing/v1alpha1/trigger_types.go index 82ac3aa648f..432c2d3eb32 100644 --- a/pkg/apis/eventing/v1alpha1/trigger_types.go +++ b/pkg/apis/eventing/v1alpha1/trigger_types.go @@ -52,6 +52,9 @@ type TriggerSpec struct { Broker string `json:"broker,omitempty"` Selector *TriggerSelectorSpec `json:"selector,omitempty"` Subscriber *SubscriberSpec `json:"subscriber,omitempty"` + + Type string `json:"type,omitempty"` + Source string `json:"source,omitempty"` } type TriggerSelectorSpec struct { @@ -60,7 +63,7 @@ type TriggerSelectorSpec struct { OPAPolicy string `json:"opaPolicy,omitEmpty"` } -var triggerCondSet = duckv1alpha1.NewLivingConditionSet(TriggerConditionBrokerExists, TriggerConditionSubscriberFound) +var triggerCondSet = duckv1alpha1.NewLivingConditionSet(TriggerConditionBrokerExists, TriggerConditionSubscribed) // TriggerStatus represents the current state of a Trigger. type TriggerStatus struct { @@ -84,7 +87,7 @@ const ( TriggerConditionBrokerExists duckv1alpha1.ConditionType = "BrokerExists" - TriggerConditionSubscriberFound duckv1alpha1.ConditionType = "SubscriberFound" + TriggerConditionSubscribed duckv1alpha1.ConditionType = "Subscribed" ) // GetCondition returns the condition currently associated with the given type, or nil. @@ -110,12 +113,12 @@ func (ts *TriggerStatus) MarkBrokerDoesNotExists() { triggerCondSet.Manage(ts).MarkFalse(TriggerConditionBrokerExists, "doesNotExist", "Broker does not exist") } -func (ts *TriggerStatus) MarkSubscriberFound() { - triggerCondSet.Manage(ts).MarkTrue(TriggerConditionSubscriberFound) +func (ts *TriggerStatus) MarkSubscribed() { + triggerCondSet.Manage(ts).MarkTrue(TriggerConditionSubscribed) } -func (ts *TriggerStatus) MarkSubscriberNotFound(reason, messageFormat string, messageA ...interface{}) { - triggerCondSet.Manage(ts).MarkFalse(TriggerConditionSubscriberFound, reason, messageFormat, messageA...) +func (ts *TriggerStatus) MarkNotSubscribed(reason, messageFormat string, messageA ...interface{}) { + triggerCondSet.Manage(ts).MarkFalse(TriggerConditionSubscribed, reason, messageFormat, messageA...) } // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object diff --git a/pkg/controller/eventing/broker/reconcile.go b/pkg/controller/eventing/broker/reconcile.go index e46d4b263d1..b9daa891a69 100644 --- a/pkg/controller/eventing/broker/reconcile.go +++ b/pkg/controller/eventing/broker/reconcile.go @@ -78,7 +78,7 @@ func (r *reconciler) Reconcile(request reconcile.Request) (reconcile.Result, err r.recorder.Event(broker, corev1.EventTypeNormal, brokerReconciled, "Broker reconciled") } - if _, err := r.updateStatus(broker.DeepCopy()); err != nil { + if _, err = r.updateStatus(broker.DeepCopy()); err != nil { logging.FromContext(ctx).Error("Failed to update Broker status", zap.Error(err)) r.recorder.Eventf(broker, corev1.EventTypeWarning, brokerUpdateStatusFailed, "Failed to update Broker's status: %v", err) return reconcile.Result{}, err diff --git a/pkg/controller/eventing/trigger/provider.go b/pkg/controller/eventing/trigger/provider.go new file mode 100644 index 00000000000..316f3312766 --- /dev/null +++ b/pkg/controller/eventing/trigger/provider.go @@ -0,0 +1,113 @@ +/* +Copyright 2018 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT 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 trigger + +import ( + "sync" + + "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" + "go.uber.org/zap" + "k8s.io/client-go/dynamic" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/record" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller" + "sigs.k8s.io/controller-runtime/pkg/handler" + "sigs.k8s.io/controller-runtime/pkg/manager" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + "sigs.k8s.io/controller-runtime/pkg/source" +) + +const ( + // controllerAgentName is the string used by this controller to identify + // itself when creating events. + controllerAgentName = "trigger-controller" +) + +type reconciler struct { + client client.Client + restConfig *rest.Config + dynamicClient dynamic.Interface + recorder record.EventRecorder + + triggersLock sync.RWMutex + triggers map[string]map[reconcile.Request]bool + + logger *zap.Logger +} + +// Verify the struct implements reconcile.Reconciler +var _ reconcile.Reconciler = &reconciler{} + +// ProvideController returns a function that returns a Broker controller. +func ProvideController(logger *zap.Logger) func(manager.Manager) (controller.Controller, error) { + return func(mgr manager.Manager) (controller.Controller, error) { + // Setup a new controller to Reconcile Brokers. + r := &reconciler{ + recorder: mgr.GetRecorder(controllerAgentName), + logger: logger, + } + c, err := controller.New(controllerAgentName, mgr, controller.Options{ + Reconciler: r, + }) + if err != nil { + return nil, err + } + + // Watch Subscription events and enqueue Subscription object key. + if err = c.Watch(&source.Kind{Type: &v1alpha1.Trigger{}}, &handler.EnqueueRequestForObject{}); err != nil { + return nil, err + } + + // TODO Make this much, much more efficient. + if err = c.Watch(&source.Kind{Type: &v1alpha1.Channel{}}, &handler.EnqueueRequestsFromMapFunc{ToRequests: &mapAllTriggers{r}}); err != nil { + return nil, err + } + + return c, nil + } +} + +func (r *reconciler) InjectClient(c client.Client) error { + r.client = c + return nil +} + +func (r *reconciler) InjectConfig(c *rest.Config) error { + r.restConfig = c + var err error + r.dynamicClient, err = dynamic.NewForConfig(c) + return err +} + +type mapAllTriggers struct { + r *reconciler +} + +func (m *mapAllTriggers) Map(o handler.MapObject) []reconcile.Request { + m.r.triggersLock.RLock() + defer m.r.triggersLock.RUnlock() + triggersInNamespace := m.r.triggers[o.Meta.GetNamespace()] + if triggersInNamespace == nil { + return []reconcile.Request{} + } + reqs := make([]reconcile.Request, 0, len(triggersInNamespace)) + for name := range triggersInNamespace { + reqs = append(reqs, name) + } + return reqs +} diff --git a/pkg/controller/eventing/trigger/reconcile.go b/pkg/controller/eventing/trigger/reconcile.go new file mode 100644 index 00000000000..b993beeed1c --- /dev/null +++ b/pkg/controller/eventing/trigger/reconcile.go @@ -0,0 +1,366 @@ +/* +Copyright 2018 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT 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 trigger + +import ( + "context" + "fmt" + + "k8s.io/apimachinery/pkg/labels" + + "k8s.io/apimachinery/pkg/runtime/schema" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/knative/eventing/pkg/provisioners" + "k8s.io/apimachinery/pkg/types" + + "github.com/knative/eventing/pkg/provisioners/gcppubsub/util/logging" + "go.uber.org/zap" + k8serrors "k8s.io/apimachinery/pkg/api/errors" + + "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/equality" + "k8s.io/apimachinery/pkg/api/errors" + "sigs.k8s.io/controller-runtime/pkg/client" + runtimeclient "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/reconcile" +) + +const ( + finalizerName = controllerAgentName + + eventTypeKey = "eventing.knative.dev/broker/eventType" + + // Name of the corev1.Events emitted from the reconciliation process + triggerReconciled = "TriggerReconciled" + triggerUpdateStatusFailed = "TriggerUpdateStatusFailed" +) + +// Reconcile compares the actual state with the desired, and attempts to +// converge the two. It then updates the Status block of the Trigger resource +// with the current status of the resource. +func (r *reconciler) Reconcile(request reconcile.Request) (reconcile.Result, error) { + ctx := context.TODO() + ctx = logging.WithLogger(ctx, r.logger.With(zap.Any("request", request))) + + trigger := &v1alpha1.Trigger{} + err := r.client.Get(context.TODO(), request.NamespacedName, trigger) + + if errors.IsNotFound(err) { + logging.FromContext(ctx).Info("Could not find Trigger") + return reconcile.Result{}, nil + } + + if err != nil { + logging.FromContext(ctx).Error("Could not Get Trigger", zap.Error(err)) + return reconcile.Result{}, err + } + + // Reconcile this copy of the Trigger and then write back any status updates regardless of + // whether the reconcile error out. + reconcileErr := r.reconcile(ctx, trigger) + if reconcileErr != nil { + logging.FromContext(ctx).Error("Error reconciling Trigger", zap.Error(reconcileErr)) + } else { + logging.FromContext(ctx).Debug("Trigger reconciled") + r.recorder.Event(trigger, corev1.EventTypeNormal, triggerReconciled, "Trigger reconciled") + } + + if _, err = r.updateStatus(trigger.DeepCopy()); err != nil { + logging.FromContext(ctx).Error("Failed to update Trigger status", zap.Error(err)) + r.recorder.Eventf(trigger, corev1.EventTypeWarning, triggerUpdateStatusFailed, "Failed to update Trigger's status: %v", err) + return reconcile.Result{}, err + } + + // Requeue if the resource is not ready: + return reconcile.Result{}, err +} + +func (r *reconciler) reconcile(ctx context.Context, t *v1alpha1.Trigger) error { + t.Status.InitializeConditions() + + // 1. Verify the Broker exists. + // 2. Determine subscribers. + // 3. Look over all subscribable resources and subscribe to the correct ones. + // 4. [Do not do for the prototype] Inject a filter on every subscription. + + if t.DeletionTimestamp != nil { + // Everything is cleaned up by the garbage collector. + r.removeFromTriggers(t) + provisioners.RemoveFinalizer(t, finalizerName) + return nil + } + + provisioners.AddFinalizer(t, finalizerName) + r.AddToTriggers(t) + + broker, err := r.getBroker(ctx, t) + if err != nil { + logging.FromContext(ctx).Error("Unable to get the Broker", zap.Error(err)) + t.Status.MarkBrokerDoesNotExists() + return err + } + t.Status.MarkBrokerExists() + + subscribables, err := r.getRelevantSubscribables(ctx, t, broker.Spec.Selector) + if err != nil { + logging.FromContext(ctx).Error("Unable to get relevant subscribables", zap.Error(err)) + return err + } + + err = r.subscribeAll(ctx, t, subscribables) + if err != nil { + logging.FromContext(ctx).Error("Unable to Subscribe", zap.Error(err)) + t.Status.MarkNotSubscribed("notSubscribed", "%v", err) + return err + } + t.Status.MarkSubscribed() + + return nil +} + +func (r *reconciler) AddToTriggers(t *v1alpha1.Trigger) { + name := reconcile.Request{ + NamespacedName: types.NamespacedName{ + Namespace: t.Namespace, + Name: t.Name, + }, + } + + // We will be reconciling an already existing Trigger far more often than adding a new one, so + // check with a read lock before using the write lock. + r.triggersLock.RLock() + triggersInNamespace := r.triggers[t.Namespace] + var present bool + if triggersInNamespace != nil { + _, present = triggersInNamespace[name] + } else { + present = false + } + r.triggersLock.RUnlock() + + if present { + // Already present in the map. + return + } + + r.triggersLock.Lock() + triggersInNamespace = r.triggers[t.Namespace] + if triggersInNamespace == nil { + r.triggers[t.Namespace] = make(map[reconcile.Request]bool) + triggersInNamespace = r.triggers[t.Namespace] + } + triggersInNamespace[name] = false + r.triggersLock.Unlock() +} + +func (r *reconciler) removeFromTriggers(t *v1alpha1.Trigger) { + name := reconcile.Request{ + NamespacedName: types.NamespacedName{ + Namespace: t.Namespace, + Name: t.Name, + }, + } + + r.triggersLock.Lock() + triggersInNamespace := r.triggers[t.Namespace] + if triggersInNamespace != nil { + delete(triggersInNamespace, name) + } + r.triggersLock.Unlock() +} + +// updateStatus may in fact update the trigger's finalizers in addition to the status +func (r *reconciler) updateStatus(trigger *v1alpha1.Trigger) (*v1alpha1.Trigger, error) { + objectKey := client.ObjectKey{Namespace: trigger.Namespace, Name: trigger.Name} + latestTrigger := &v1alpha1.Trigger{} + + if err := r.client.Get(context.TODO(), objectKey, latestTrigger); err != nil { + return nil, err + } + + triggerChanged := false + + if !equality.Semantic.DeepEqual(latestTrigger.Finalizers, trigger.Finalizers) { + latestTrigger.SetFinalizers(trigger.ObjectMeta.Finalizers) + if err := r.client.Update(context.TODO(), latestTrigger); err != nil { + return nil, err + } + triggerChanged = true + } + + if equality.Semantic.DeepEqual(latestTrigger.Status, trigger.Status) { + return latestTrigger, nil + } + + if triggerChanged { + // Refetch + latestTrigger = &v1alpha1.Trigger{} + if err := r.client.Get(context.TODO(), objectKey, latestTrigger); err != nil { + return nil, err + } + } + + latestTrigger.Status = trigger.Status + if err := r.client.Status().Update(context.TODO(), latestTrigger); err != nil { + return nil, err + } + + return latestTrigger, nil +} + +func (r *reconciler) getBroker(ctx context.Context, t *v1alpha1.Trigger) (*v1alpha1.Broker, error) { + broker := &v1alpha1.Broker{} + name := types.NamespacedName{ + Namespace: t.Namespace, + Name: t.Spec.Broker, + } + err := r.client.Get(ctx, name, broker) + return broker, err +} + +func (r *reconciler) getRelevantSubscribables(ctx context.Context, t *v1alpha1.Trigger, selector *metav1.LabelSelector) ([]v1alpha1.Channel, error) { + selector.MatchLabels[eventTypeKey] = t.Spec.Type + + subscribables := make([]v1alpha1.Channel, 0) + opts := &client.ListOptions{ + // TODO this is here because the fake client needs it. Remove this when it's no longer + // needed. + Raw: &metav1.ListOptions{ + TypeMeta: metav1.TypeMeta{ + APIVersion: v1alpha1.SchemeGroupVersion.String(), + Kind: "Channel", + }, + }, + Namespace: t.Namespace, + } + for { + list := v1alpha1.ChannelList{} + err := r.client.List(ctx, opts, &list) + if err != nil { + return nil, err + } + for _, s := range list.Items { + subscribables = append(subscribables, s) + if list.Continue != "" { + opts.Raw.Continue = list.Continue + } else { + return subscribables, nil + } + } + } +} + +func (r *reconciler) subscribeAll(ctx context.Context, t *v1alpha1.Trigger, subscribables []v1alpha1.Channel) error { + for _, subscribable := range subscribables { + _, err := r.subscribe(ctx, t, &subscribable) + if err != nil { + return err + } + } + return nil +} + +func (r *reconciler) subscribe(ctx context.Context, t *v1alpha1.Trigger, subscribable *v1alpha1.Channel) (*v1alpha1.Subscription, error) { + expected := makeSubscription(t, subscribable) + + sub, err := r.getSubscription(ctx, t, subscribable) + // If the resource doesn't exist, we'll create it + if k8serrors.IsNotFound(err) { + sub = expected + err = r.client.Create(ctx, sub) + if err != nil { + return nil, err + } + return sub, nil + } else if err != nil { + return nil, err + } + + // Update Subscription if it has changed. + if !equality.Semantic.DeepDerivative(expected.Spec, sub.Spec) { + sub.Spec = expected.Spec + err = r.client.Update(ctx, sub) + if err != nil { + return nil, err + } + } + return sub, nil +} + +func (r *reconciler) getSubscription(ctx context.Context, t *v1alpha1.Trigger, subscribable *v1alpha1.Channel) (*v1alpha1.Subscription, error) { + list := &v1alpha1.SubscriptionList{} + opts := &runtimeclient.ListOptions{ + Namespace: t.Namespace, + LabelSelector: labels.SelectorFromSet(subscriptionLabels(t)), + // TODO this is here because the fake client needs it. Remove this when it's no longer + // needed. + Raw: &metav1.ListOptions{ + TypeMeta: metav1.TypeMeta{ + APIVersion: v1alpha1.SchemeGroupVersion.String(), + Kind: "Subscription", + }, + }, + } + + err := r.client.List(ctx, opts, list) + if err != nil { + return nil, err + } + for _, s := range list.Items { + if metav1.IsControlledBy(&s, t) { + return &s, nil + } + } + + return nil, k8serrors.NewNotFound(schema.GroupResource{}, "") +} + +func makeSubscription(t *v1alpha1.Trigger, subscribable *v1alpha1.Channel) *v1alpha1.Subscription { + return &v1alpha1.Subscription{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: t.Namespace, + GenerateName: fmt.Sprintf("%s-%s-", t.Spec.Broker, t.Name), + OwnerReferences: []metav1.OwnerReference{ + *metav1.NewControllerRef(t, schema.GroupVersionKind{ + Group: t.GroupVersionKind().Group, + Version: t.GroupVersionKind().Version, + Kind: t.GroupVersionKind().Kind, + }), + }, + Labels: subscriptionLabels(t), + }, + Spec: v1alpha1.SubscriptionSpec{ + Channel: corev1.ObjectReference{ + APIVersion: subscribable.APIVersion, + Kind: subscribable.Kind, + Namespace: subscribable.Namespace, + Name: subscribable.Name, + }, + Subscriber: t.Spec.Subscriber, + }, + } +} + +func subscriptionLabels(t *v1alpha1.Trigger) map[string]string { + return map[string]string{ + "eventing.knative.dev/broker": t.Spec.Broker, + "eventing.knative.dev/trigger": t.Name, + } +} diff --git a/pkg/controller/eventing/trigger/resources/activator.go b/pkg/controller/eventing/trigger/resources/activator.go new file mode 100644 index 00000000000..1de0820eef1 --- /dev/null +++ b/pkg/controller/eventing/trigger/resources/activator.go @@ -0,0 +1,75 @@ +/* +Copyright 2018 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT 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 resources + +import ( + "encoding/json" + "fmt" + + eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" + servingv1alpha1 "github.com/knative/serving/pkg/apis/serving/v1alpha1" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +type ActivatorArgs struct { + Broker *eventingv1alpha1.Broker + Image string + ServiceAccountName string +} + +func MakeActivator(args *ActivatorArgs) (*servingv1alpha1.Service, error) { + templateJson, err := json.Marshal(args.Broker.Spec.ChannelTemplate) + if err != nil { + return nil, err + } + + return &servingv1alpha1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: args.Broker.Namespace, + Name: fmt.Sprintf("%s-broker-activator", args.Broker.Name), + OwnerReferences: []metav1.OwnerReference{ + *metav1.NewControllerRef(args.Broker, schema.GroupVersionKind{ + Group: args.Broker.GroupVersionKind().Group, + Version: args.Broker.GroupVersionKind().Version, + Kind: args.Broker.GroupVersionKind().Kind, + }), + }, + }, + Spec: servingv1alpha1.ServiceSpec{ + RunLatest: &servingv1alpha1.RunLatestType{ + Configuration: servingv1alpha1.ConfigurationSpec{ + RevisionTemplate: servingv1alpha1.RevisionTemplateSpec{ + Spec: servingv1alpha1.RevisionSpec{ + ServiceAccountName: args.ServiceAccountName, + Container: v1.Container{ + Image: args.Image, + Env: []v1.EnvVar{ + { + Name: "CHANNEL_TEMPLATE", + Value: string(templateJson), + }, + }, + }, + }, + }, + }, + }, + }, + }, nil +} diff --git a/pkg/controller/eventing/trigger/resources/router.go b/pkg/controller/eventing/trigger/resources/router.go new file mode 100644 index 00000000000..baf8ac4b39c --- /dev/null +++ b/pkg/controller/eventing/trigger/resources/router.go @@ -0,0 +1,80 @@ +/* +Copyright 2018 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT 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 resources + +import ( + "encoding/json" + "fmt" + + eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" + servingv1alpha1 "github.com/knative/serving/pkg/apis/serving/v1alpha1" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +type RouterArgs struct { + Broker *eventingv1alpha1.Broker + Image string + ServiceAccountName string + NeedsActivationHost string +} + +func MakeRouter(args *RouterArgs) (*servingv1alpha1.Service, error) { + selectorJson, err := json.Marshal(args.Broker.Spec.Selector) + if err != nil { + return nil, err + } + + return &servingv1alpha1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: args.Broker.Namespace, + Name: fmt.Sprintf("%s-broker", args.Broker.Name), + OwnerReferences: []metav1.OwnerReference{ + *metav1.NewControllerRef(args.Broker, schema.GroupVersionKind{ + Group: args.Broker.GroupVersionKind().Group, + Version: args.Broker.GroupVersionKind().Version, + Kind: args.Broker.GroupVersionKind().Kind, + }), + }, + }, + Spec: servingv1alpha1.ServiceSpec{ + RunLatest: &servingv1alpha1.RunLatestType{ + Configuration: servingv1alpha1.ConfigurationSpec{ + RevisionTemplate: servingv1alpha1.RevisionTemplateSpec{ + Spec: servingv1alpha1.RevisionSpec{ + ServiceAccountName: args.ServiceAccountName, + Container: v1.Container{ + Image: args.Image, + Env: []v1.EnvVar{ + { + Name: "NEEDS_ACTIVATION_HOST", + Value: args.NeedsActivationHost, + }, + { + Name: "LABEL_SELECTOR", + Value: string(selectorJson), + }, + }, + }, + }, + }, + }, + }, + }, + }, nil +} diff --git a/pkg/provisioners/channel_util.go b/pkg/provisioners/channel_util.go index d84992e5664..ca5dc675fbc 100644 --- a/pkg/provisioners/channel_util.go +++ b/pkg/provisioners/channel_util.go @@ -46,21 +46,21 @@ const ( FinalizerAdded AddFinalizerResult = true ) -// AddFinalizer adds finalizerName to the Channel. -func AddFinalizer(c *eventingv1alpha1.Channel, finalizerName string) AddFinalizerResult { - finalizers := sets.NewString(c.Finalizers...) +// AddFinalizer adds finalizerName to the Object. +func AddFinalizer(o metav1.Object, finalizerName string) AddFinalizerResult { + finalizers := sets.NewString(o.GetFinalizers()...) if finalizers.Has(finalizerName) { return FinalizerAlreadyPresent } finalizers.Insert(finalizerName) - c.Finalizers = finalizers.List() + o.SetFinalizers(finalizers.List()) return FinalizerAdded } -func RemoveFinalizer(c *eventingv1alpha1.Channel, finalizerName string) { - finalizers := sets.NewString(c.Finalizers...) +func RemoveFinalizer(o metav1.Object, finalizerName string) { + finalizers := sets.NewString(o.GetFinalizers()...) finalizers.Delete(finalizerName) - c.Finalizers = finalizers.List() + o.SetFinalizers(finalizers.List()) } func CreateK8sService(ctx context.Context, client runtimeClient.Client, c *eventingv1alpha1.Channel) (*corev1.Service, error) { From da9fe36fd6d07709fe099630a3609b663291f050 Mon Sep 17 00:00:00 2001 From: Adam Harwayne Date: Mon, 4 Feb 2019 15:58:52 -0800 Subject: [PATCH 008/221] Initial work on the new model and its corresponding broker controller. --- Gopkg.lock | 1 + pkg/apis/eventing/v1alpha1/broker_defaults.go | 42 +- pkg/apis/eventing/v1alpha1/broker_types.go | 37 +- .../eventing/v1alpha1/broker_validation.go | 60 +- .../eventing/v1alpha1/trigger_defaults.go | 3 + pkg/apis/eventing/v1alpha1/trigger_types.go | 21 +- .../eventing/v1alpha1/trigger_validation.go | 25 +- .../v1alpha1/zz_generated.deepcopy.go | 91 +-- pkg/controller/eventing/broker/provider.go | 8 +- pkg/controller/eventing/broker/reconcile.go | 153 +++-- .../eventing/broker/resources/activator.go | 75 --- .../eventing/broker/resources/filter.go | 107 +++ .../eventing/broker/resources/ingress.go | 112 ++++ .../eventing/broker/resources/router.go | 80 --- third_party/VENDOR-LICENSE | 625 +++++++++++++++++- 15 files changed, 980 insertions(+), 460 deletions(-) delete mode 100644 pkg/controller/eventing/broker/resources/activator.go create mode 100644 pkg/controller/eventing/broker/resources/filter.go create mode 100644 pkg/controller/eventing/broker/resources/ingress.go delete mode 100644 pkg/controller/eventing/broker/resources/router.go diff --git a/Gopkg.lock b/Gopkg.lock index 78ddd9acdc2..69eb95c7f07 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -1259,6 +1259,7 @@ "golang.org/x/sync/errgroup", "google.golang.org/api/option", "gopkg.in/yaml.v2", + "k8s.io/api/apps/v1", "k8s.io/api/core/v1", "k8s.io/api/rbac/v1", "k8s.io/apimachinery/pkg/api/equality", diff --git a/pkg/apis/eventing/v1alpha1/broker_defaults.go b/pkg/apis/eventing/v1alpha1/broker_defaults.go index c8a23a6eda5..890e4fbecf0 100644 --- a/pkg/apis/eventing/v1alpha1/broker_defaults.go +++ b/pkg/apis/eventing/v1alpha1/broker_defaults.go @@ -16,8 +16,6 @@ limitations under the License. package v1alpha1 -import v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - const ( brokerLabel = "eventing.knative.dev/broker" ) @@ -27,45 +25,7 @@ func (b *Broker) SetDefaults() { } func (bs *BrokerSpec) SetDefaults(brokerName string) { - if bs.Selector == nil { - bs.Selector = defaultBrokerSpecSelector(brokerName) - } - if bs.ChannelTemplate == nil { - bs.ChannelTemplate = defaultBrokerSpecChannelTemplate(brokerName) - } - if len(bs.SubscribableResources) == 0 { - bs.SubscribableResources = defaultBrokerSpecSubscribableResources() - } -} - -func defaultBrokerLabels(brokerName string) map[string]string { - return map[string]string{ - brokerLabel: brokerName, - } + // None } -func defaultBrokerSpecSelector(brokerName string) *v1.LabelSelector { - return &v1.LabelSelector{ - MatchLabels: defaultBrokerLabels(brokerName), - } -} -func defaultBrokerSpecChannelTemplate(brokerName string) *ChannelTemplateSpec { - return &ChannelTemplateSpec{ - Metadata: v1.ObjectMeta{ - Labels: defaultBrokerLabels(brokerName), - }, - // Spec is left blank so that the created Channel defaulter will default the provisioner - // and arguments when the Channel is created. - } -} - -func defaultBrokerSpecSubscribableResources() []v1.GroupVersionKind { - return []v1.GroupVersionKind{ - { - Group: "eventing.knative.dev", - Version: "v1alpha1", - Kind: "Channel", - }, - } -} diff --git a/pkg/apis/eventing/v1alpha1/broker_types.go b/pkg/apis/eventing/v1alpha1/broker_types.go index 20a6a945c3f..d3c2c5b4e2a 100644 --- a/pkg/apis/eventing/v1alpha1/broker_types.go +++ b/pkg/apis/eventing/v1alpha1/broker_types.go @@ -49,17 +49,10 @@ var _ runtime.Object = (*Broker)(nil) var _ webhook.GenericCRD = (*Broker)(nil) type BrokerSpec struct { - Selector *metav1.LabelSelector `json:"selector,omitempty"` - ChannelTemplate *ChannelTemplateSpec `json:"channelTemplate,omitempty"` - SubscribableResources []metav1.GroupVersionKind `json:"subscribableResources,omitempty"` + ChannelTemplate *ChannelSpec `json:"channelTemplate,omitempty"` } -type ChannelTemplateSpec struct { - Metadata metav1.ObjectMeta `json:"metadata,omitempty"` - Spec *ChannelSpec `json:"spec,omitempty"` -} - -var brokerCondSet = duckv1alpha1.NewLivingConditionSet(BrokerConditionChannelTemplateSelector, BrokerConditionSubscribableResourcesExist, BrokerConditionSubscribableResourcesExist, BrokerConditionAddressable) +var brokerCondSet = duckv1alpha1.NewLivingConditionSet(BrokerConditionIngress, BrokerConditionChannel, BrokerConditionFilter, BrokerConditionAddressable) // BrokerStatus represents the current state of a Broker. type BrokerStatus struct { @@ -88,11 +81,11 @@ type BrokerStatus struct { const ( BrokerConditionReady = duckv1alpha1.ConditionReady - BrokerConditionChannelTemplateSelector duckv1alpha1.ConditionType = "ChannelTemplateSelector" + BrokerConditionIngress duckv1alpha1.ConditionType = "Ingress" - BrokerConditionSubscribableResourcesExist duckv1alpha1.ConditionType = "SubscribableResourcesExist" + BrokerConditionChannel duckv1alpha1.ConditionType = "Channel" - BrokerConditionRouterAndActivatorExist duckv1alpha1.ConditionType = "RouterAndActivatorCreated" + BrokerConditionFilter duckv1alpha1.ConditionType = "Filter" BrokerConditionAddressable duckv1alpha1.ConditionType = "Addressable" ) @@ -112,24 +105,24 @@ func (bs *BrokerStatus) InitializeConditions() { brokerCondSet.Manage(bs).InitializeConditions() } -func (bs *BrokerStatus) MarkChannelTemplateMatchesSelector() { - brokerCondSet.Manage(bs).MarkTrue(BrokerConditionChannelTemplateSelector) +func (bs *BrokerStatus) MarkIngressReady() { + brokerCondSet.Manage(bs).MarkTrue(BrokerConditionIngress) } -func (bs *BrokerStatus) MarkChannelTemplateDoesNotMatchSelector() { - brokerCondSet.Manage(bs).MarkFalse(BrokerConditionChannelTemplateSelector, "selectorDoesNotMatchTemplate", "`spec.selector` does not match `spec.channelTempalte.meta.labels`") +func (bs *BrokerStatus) MarkIngressFailed(err error) { + brokerCondSet.Manage(bs).MarkFalse(BrokerConditionIngress, "failed", "%v", err) } -func (bs *BrokerStatus) MarkSubscribableResourcesExist() { - brokerCondSet.Manage(bs).MarkTrue(BrokerConditionSubscribableResourcesExist) +func (bs *BrokerStatus) MarkChannelReady() { + brokerCondSet.Manage(bs).MarkTrue(BrokerConditionChannel) } -func (bs *BrokerStatus) MarkSubscribableResourcesDoNotExist(dontExist []metav1.GroupVersionKind) { - brokerCondSet.Manage(bs).MarkFalse(BrokerConditionSubscribableResourcesExist, "resourcesDontExist", "The following resources do not exist: %v", dontExist) +func (bs *BrokerStatus) MarkChannelFailed(err error) { + brokerCondSet.Manage(bs).MarkFalse(BrokerConditionChannel, "failed", "%v", err) } -func (bs *BrokerStatus) MarkRouterAndActivatorExist() { - brokerCondSet.Manage(bs).MarkTrue(BrokerConditionRouterAndActivatorExist) +func (bs *BrokerStatus) MarkFilterReady() { + brokerCondSet.Manage(bs).MarkTrue(BrokerConditionFilter) } // SetAddress makes this Channel addressable by setting the hostname. It also diff --git a/pkg/apis/eventing/v1alpha1/broker_validation.go b/pkg/apis/eventing/v1alpha1/broker_validation.go index 98d31a4b9cd..c7954c26d15 100644 --- a/pkg/apis/eventing/v1alpha1/broker_validation.go +++ b/pkg/apis/eventing/v1alpha1/broker_validation.go @@ -17,12 +17,7 @@ limitations under the License. package v1alpha1 import ( - "fmt" - - "github.com/google/go-cmp/cmp" "github.com/knative/pkg/apis" - "k8s.io/apimachinery/pkg/api/equality" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) func (b *Broker) Validate() *apis.FieldError { @@ -30,63 +25,10 @@ func (b *Broker) Validate() *apis.FieldError { } func (bs *BrokerSpec) Validate() *apis.FieldError { - var errs *apis.FieldError - if isSelectorNotPresentOrEmpty(bs.Selector) { - fe := apis.ErrMissingField("selector") - fe.Details = "the Broker must have a selector" - errs = errs.Also(fe) - } - - if bs.ChannelTemplate == nil { - fe := apis.ErrMissingField("channelTemplate") - fe.Details = "the Broker must have a channelTemplate" - errs = errs.Also(fe) - } else if !selectorMatchesTemplateLabels(bs.Selector, bs.ChannelTemplate) { - fe := apis.ErrInvalidValue(fmt.Sprint(bs.ChannelTemplate.Metadata.Labels), "channelTemplate.metadata.labels") - errs = errs.Also(fe) - } - - if !channelsInSubscribableResources(bs.SubscribableResources) { - fe := apis.ErrInvalidValue(fmt.Sprint(bs.SubscribableResources), "subscribableResources") - errs = errs.Also(fe) - } - - return errs -} - -func isSelectorNotPresentOrEmpty(s *v1.LabelSelector) bool { - return s == nil || equality.Semantic.DeepEqual(s, &v1.LabelSelector{}) + return nil } -func selectorMatchesTemplateLabels(s *v1.LabelSelector, ct *ChannelTemplateSpec) bool { - // TODO Improve this so it supports something other than direct label equality. - return equality.Semantic.DeepEqual(s.MatchLabels, ct.Metadata.Labels) -} - -func channelsInSubscribableResources(sr []v1.GroupVersionKind) bool { - for _, r := range sr { - if r.Group == "eventing.knative.dev" && r.Version == "v1alpha1" && r.Kind == "Channel" { - return true - } - } - return false -} func (b *Broker) CheckImmutableFields(og apis.Immutable) *apis.FieldError { - original, ok := og.(*Broker) - if !ok { - return &apis.FieldError{Message: "The provided original was not a Broker"} - } - if original == nil { - return nil - } - - if diff := cmp.Diff(original.Spec.Selector, b.Spec.Selector); diff != "" { - return &apis.FieldError{ - Message: "Immutable fields changed (-old +new)", - Paths: []string{"spec", "selector"}, - Details: diff, - } - } return nil } diff --git a/pkg/apis/eventing/v1alpha1/trigger_defaults.go b/pkg/apis/eventing/v1alpha1/trigger_defaults.go index 732d9fde924..ac2dfdf843f 100644 --- a/pkg/apis/eventing/v1alpha1/trigger_defaults.go +++ b/pkg/apis/eventing/v1alpha1/trigger_defaults.go @@ -24,4 +24,7 @@ func (ts *TriggerSpec) SetDefaults() { if ts.Broker == "" { ts.Broker = "default" } + if ts.Type == "" { + ts.Type = "ANY" + } } diff --git a/pkg/apis/eventing/v1alpha1/trigger_types.go b/pkg/apis/eventing/v1alpha1/trigger_types.go index 432c2d3eb32..e6dc53bb9a8 100644 --- a/pkg/apis/eventing/v1alpha1/trigger_types.go +++ b/pkg/apis/eventing/v1alpha1/trigger_types.go @@ -50,20 +50,13 @@ var _ webhook.GenericCRD = (*Trigger)(nil) type TriggerSpec struct { Broker string `json:"broker,omitempty"` - Selector *TriggerSelectorSpec `json:"selector,omitempty"` Subscriber *SubscriberSpec `json:"subscriber,omitempty"` Type string `json:"type,omitempty"` Source string `json:"source,omitempty"` } -type TriggerSelectorSpec struct { - Header map[string]string `json:"header,omitempty"` - HeaderExpression []metav1.LabelSelectorRequirement `json:"headerExpression,omitEmpty"` - OPAPolicy string `json:"opaPolicy,omitEmpty"` -} - -var triggerCondSet = duckv1alpha1.NewLivingConditionSet(TriggerConditionBrokerExists, TriggerConditionSubscribed) +var triggerCondSet = duckv1alpha1.NewLivingConditionSet(TriggerConditionBrokerExists, TriggerConditionKubernetesService, TriggerConditionVirtualService, TriggerConditionSubscribed) // TriggerStatus represents the current state of a Trigger. type TriggerStatus struct { @@ -87,6 +80,10 @@ const ( TriggerConditionBrokerExists duckv1alpha1.ConditionType = "BrokerExists" + TriggerConditionKubernetesService duckv1alpha1.ConditionType = "KubernetesService" + + TriggerConditionVirtualService duckv1alpha1.ConditionType = "VirtualService" + TriggerConditionSubscribed duckv1alpha1.ConditionType = "Subscribed" ) @@ -113,6 +110,14 @@ func (ts *TriggerStatus) MarkBrokerDoesNotExists() { triggerCondSet.Manage(ts).MarkFalse(TriggerConditionBrokerExists, "doesNotExist", "Broker does not exist") } +func (ts *TriggerSpec) MarkKubernetesServiceExists() { + triggerCondSet.Manage(ts).MarkTrue(TriggerConditionKubernetesService) +} + +func (ts *TriggerSpec) MarkVirtualServiceExists() { + triggerCondSet.Manage(ts).MarkTrue(TriggerConditionVirtualService) +} + func (ts *TriggerStatus) MarkSubscribed() { triggerCondSet.Manage(ts).MarkTrue(TriggerConditionSubscribed) } diff --git a/pkg/apis/eventing/v1alpha1/trigger_validation.go b/pkg/apis/eventing/v1alpha1/trigger_validation.go index 6ff7301e244..9d0178a464f 100644 --- a/pkg/apis/eventing/v1alpha1/trigger_validation.go +++ b/pkg/apis/eventing/v1alpha1/trigger_validation.go @@ -19,7 +19,6 @@ package v1alpha1 import ( "github.com/google/go-cmp/cmp" "github.com/knative/pkg/apis" - "k8s.io/apimachinery/pkg/api/equality" ) func (t *Trigger) Validate() *apis.FieldError { @@ -33,10 +32,8 @@ func (ts *TriggerSpec) Validate() *apis.FieldError { errs = errs.Also(fe) } - if ts.Selector == nil { - fe := apis.ErrMissingField("selector") - errs = errs.Also(fe) - } else if fe := multipleSelectorsSet(ts.Selector); fe != nil { + if ts.Type == "" { + fe := apis.ErrMissingField("type") errs = errs.Also(fe) } @@ -50,24 +47,6 @@ func (ts *TriggerSpec) Validate() *apis.FieldError { return errs } -func multipleSelectorsSet(s *TriggerSelectorSpec) *apis.FieldError { - var fields []string - if !equality.Semantic.DeepEqual(s.Header, map[string]string{}) { - fields = append(fields, "header") - } - if len(s.HeaderExpression) > 0 { - fields = append(fields, "headerExpression") - } - if s.OPAPolicy != "" { - fields = append(fields, "opaPolicy") - } - - if len(fields) != 1 { - return apis.ErrMultipleOneOf(fields...) - } - return nil -} - func (t *Trigger) CheckImmutableFields(og apis.Immutable) *apis.FieldError { original, ok := og.(*Trigger) if !ok { diff --git a/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go index 77046af1c1d..fc8f77d0aee 100644 --- a/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go @@ -23,8 +23,7 @@ package v1alpha1 import ( apis_duck_v1alpha1 "github.com/knative/eventing/pkg/apis/duck/v1alpha1" duck_v1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" - core_v1 "k8s.io/api/core/v1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + v1 "k8s.io/api/core/v1" runtime "k8s.io/apimachinery/pkg/runtime" ) @@ -92,29 +91,15 @@ func (in *BrokerList) DeepCopyObject() runtime.Object { // 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.Selector != nil { - in, out := &in.Selector, &out.Selector - if *in == nil { - *out = nil - } else { - *out = new(v1.LabelSelector) - (*in).DeepCopyInto(*out) - } - } if in.ChannelTemplate != nil { in, out := &in.ChannelTemplate, &out.ChannelTemplate if *in == nil { *out = nil } else { - *out = new(ChannelTemplateSpec) + *out = new(ChannelSpec) (*in).DeepCopyInto(*out) } } - if in.SubscribableResources != nil { - in, out := &in.SubscribableResources, &out.SubscribableResources - *out = make([]v1.GroupVersionKind, len(*in)) - copy(*out, *in) - } return } @@ -138,6 +123,7 @@ func (in *BrokerStatus) DeepCopyInto(out *BrokerStatus) { (*in)[i].DeepCopyInto(&(*out)[i]) } } + out.Address = in.Address return } @@ -220,7 +206,7 @@ func (in *ChannelSpec) DeepCopyInto(out *ChannelSpec) { if *in == nil { *out = nil } else { - *out = new(core_v1.ObjectReference) + *out = new(v1.ObjectReference) **out = **in } } @@ -288,32 +274,6 @@ func (in *ChannelStatus) DeepCopy() *ChannelStatus { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ChannelTemplateSpec) DeepCopyInto(out *ChannelTemplateSpec) { - *out = *in - in.Metadata.DeepCopyInto(&out.Metadata) - if in.Spec != nil { - in, out := &in.Spec, &out.Spec - if *in == nil { - *out = nil - } else { - *out = new(ChannelSpec) - (*in).DeepCopyInto(*out) - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ChannelTemplateSpec. -func (in *ChannelTemplateSpec) DeepCopy() *ChannelTemplateSpec { - if in == nil { - return nil - } - out := new(ChannelTemplateSpec) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ClusterChannelProvisioner) DeepCopyInto(out *ClusterChannelProvisioner) { *out = *in @@ -422,7 +382,7 @@ func (in *ReplyStrategy) DeepCopyInto(out *ReplyStrategy) { if *in == nil { *out = nil } else { - *out = new(core_v1.ObjectReference) + *out = new(v1.ObjectReference) **out = **in } } @@ -447,7 +407,7 @@ func (in *SubscriberSpec) DeepCopyInto(out *SubscriberSpec) { if *in == nil { *out = nil } else { - *out = new(core_v1.ObjectReference) + *out = new(v1.ObjectReference) **out = **in } } @@ -670,48 +630,9 @@ func (in *TriggerList) DeepCopyObject() runtime.Object { return nil } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *TriggerSelectorSpec) DeepCopyInto(out *TriggerSelectorSpec) { - *out = *in - if in.Header != nil { - in, out := &in.Header, &out.Header - *out = make(map[string]string, len(*in)) - for key, val := range *in { - (*out)[key] = val - } - } - if in.HeaderExpression != nil { - in, out := &in.HeaderExpression, &out.HeaderExpression - *out = make([]v1.LabelSelectorRequirement, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TriggerSelectorSpec. -func (in *TriggerSelectorSpec) DeepCopy() *TriggerSelectorSpec { - if in == nil { - return nil - } - out := new(TriggerSelectorSpec) - in.DeepCopyInto(out) - return out -} - // 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.Selector != nil { - in, out := &in.Selector, &out.Selector - if *in == nil { - *out = nil - } else { - *out = new(TriggerSelectorSpec) - (*in).DeepCopyInto(*out) - } - } if in.Subscriber != nil { in, out := &in.Subscriber, &out.Subscriber if *in == nil { diff --git a/pkg/controller/eventing/broker/provider.go b/pkg/controller/eventing/broker/provider.go index 9315366245c..8b78d982685 100644 --- a/pkg/controller/eventing/broker/provider.go +++ b/pkg/controller/eventing/broker/provider.go @@ -44,10 +44,10 @@ type reconciler struct { logger *zap.Logger - routerImage string - routerServiceAccountName string - activatorImage string - activatorServiceAccountName string + routerImage string + routerServiceAccountName string + filterImage string + filterServiceAccountName string } // Verify the struct implements reconcile.Reconciler diff --git a/pkg/controller/eventing/broker/reconcile.go b/pkg/controller/eventing/broker/reconcile.go index b9daa891a69..720ef29a266 100644 --- a/pkg/controller/eventing/broker/reconcile.go +++ b/pkg/controller/eventing/broker/reconcile.go @@ -19,6 +19,8 @@ package broker import ( "context" "fmt" + "github.com/knative/eventing/pkg/controller" + "k8s.io/api/apps/v1" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime/schema" @@ -91,57 +93,50 @@ func (r *reconciler) Reconcile(request reconcile.Request) (reconcile.Result, err func (r *reconciler) reconcile(ctx context.Context, b *v1alpha1.Broker) error { b.Status.InitializeConditions() - // 1. Create the router. - // 2. Create the activator. - // 3. Create the filter [do not do for the prototype]. - // 4. Create the 'needs-activation' Channel. - // 5. Create Subscription from 'needs-activation' Channel to the activator. + // 1. Channel is created for all events. + // 2. Filter Deployment. + // 3. Ingress Deployment. + // 4. K8s Service that points at the Deployment. if b.DeletionTimestamp != nil { // Everything is cleaned up by the garbage collector. return nil } - // TODO Actually check this, for now the webhook ensures they are identical. - b.Status.MarkChannelTemplateMatchesSelector() - - dontExist, err := r.verifyResourcesExist(ctx, b.Spec.SubscribableResources) + c, err := r.reconcileChannel(ctx, b) if err != nil { - logging.FromContext(ctx).Error("Unable to determine if resources exist", zap.Error(err)) + logging.FromContext(ctx).Error("Problem reconciling the channel", zap.Error(err)) + b.Status.MarkChannelFailed(err) return err - } else if len(dontExist) > 0 { - b.Status.MarkSubscribableResourcesDoNotExist(dontExist) - } else { - b.Status.MarkSubscribableResourcesExist() } + b.Status.MarkChannelReady() - activator, err := r.reconcileActivator(ctx, b) + _, err = r.reconcileFilterDeployment(ctx, b) if err != nil { - logging.FromContext(ctx).Error("Problem reconciling activator", zap.Error(err)) + logging.FromContext(ctx).Error("Problem reconciling filter deployment", zap.Error(err)) return err } - - // TODO Add the filter reconciliation here. - - c, err := r.reconcileNeedsActivationChannel(ctx, b) + _, err = r.reconcileFilterService(ctx, b) if err != nil { - logging.FromContext(ctx).Error("Problem reconciling the needs activation channel", zap.Error(err)) + logging.FromContext(ctx).Error("Problem reconciling filter service", zap.Error(err)) return err } + b.Status.MarkFilterReady() - _, err = r.reconcileNeedsActivationSubscription(ctx, b, activator, c) + _, err = r.reconcileIngressDeployment(ctx, b, c) if err != nil { - logging.FromContext(ctx).Error("Problem reconciling the needs activation subscription", zap.Error(err)) + logging.FromContext(ctx).Error("Problem reconciling ingress deployment", zap.Error(err)) return err } - b.Status.MarkRouterAndActivatorExist() - router, err := r.reconcileRouter(ctx, b, c) + + svc, err := r.reconcileIngressService(ctx, b) if err != nil { - logging.FromContext(ctx).Error("Problem reconciling router", zap.Error(err)) + logging.FromContext(ctx).Error("Problem reconciling ingress Service", zap.Error(err)) return err } - b.Status.SetAddress(router.Status.Address.Hostname) + b.Status.MarkIngressReady() + b.Status.SetAddress(controller.ServiceHostName(svc.Name, svc.Namespace)) return nil } @@ -185,28 +180,27 @@ func (r *reconciler) updateStatus(broker *v1alpha1.Broker) (*v1alpha1.Broker, er return latestBroker, nil } -func (r *reconciler) verifyResourcesExist(ctx context.Context, resources []metav1.GroupVersionKind) ([]metav1.GroupVersionKind, error) { - dontExist := make([]metav1.GroupVersionKind, 0, len(resources)) - // TODO Implement, for now the webhook asserts it is only Channel, which we assume exists. - return dontExist, nil -} - -func (r *reconciler) reconcileActivator(ctx context.Context, b *v1alpha1.Broker) (*servingv1alpha1.Service, error) { - expected, err := resources.MakeActivator(&resources.ActivatorArgs{ +func (r *reconciler) reconcileFilterDeployment(ctx context.Context, b *v1alpha1.Broker) (*v1.Deployment, error) { + expected, err := resources.MakeFilterDeployment(&resources.FilterArgs{ Broker: b, - Image: r.activatorImage, - ServiceAccountName: r.activatorServiceAccountName, + Image: r.filterImage, + ServiceAccountName: r.filterServiceAccountName, }) if err != nil { return nil, err } - return r.reconcileKSvc(ctx, expected) + return r.reconcileDeployment(ctx, expected) +} + +func (r *reconciler) reconcileFilterService(ctx context.Context, b *v1alpha1.Broker) (*corev1.Service, error) { + expected := resources.MakeFilterService(b) + return r.reconcileService(ctx, expected) } -func (r *reconciler) reconcileNeedsActivationChannel(ctx context.Context, b *v1alpha1.Broker) (*v1alpha1.Channel, error) { - expected := newNeedsActivationChannel(b) +func (r *reconciler) reconcileChannel(ctx context.Context, b *v1alpha1.Broker) (*v1alpha1.Channel, error) { + expected := newChannel(b) - c, err := r.getNeedsActivationChannel(ctx, b) + c, err := r.getChannel(ctx, b) // If the resource doesn't exist, we'll create it if k8serrors.IsNotFound(err) { c = expected @@ -232,11 +226,11 @@ func (r *reconciler) reconcileNeedsActivationChannel(ctx context.Context, b *v1a return c, nil } -func (r *reconciler) getNeedsActivationChannel(ctx context.Context, b *v1alpha1.Broker) (*v1alpha1.Channel, error) { +func (r *reconciler) getChannel(ctx context.Context, b *v1alpha1.Broker) (*v1alpha1.Channel, error) { list := &v1alpha1.ChannelList{} opts := &runtimeclient.ListOptions{ Namespace: b.Namespace, - LabelSelector: labels.SelectorFromSet(needsActivationLabels(b)), + LabelSelector: labels.SelectorFromSet(channelLabels(b)), // TODO this is here because the fake client needs it. Remove this when it's no longer // needed. Raw: &metav1.ListOptions{ @@ -260,16 +254,16 @@ func (r *reconciler) getNeedsActivationChannel(ctx context.Context, b *v1alpha1. return nil, k8serrors.NewNotFound(schema.GroupResource{}, "") } -func newNeedsActivationChannel(b *v1alpha1.Broker) *v1alpha1.Channel { +func newChannel(b *v1alpha1.Broker) *v1alpha1.Channel { var spec v1alpha1.ChannelSpec - if b.Spec.ChannelTemplate != nil && b.Spec.ChannelTemplate.Spec != nil { - spec = *b.Spec.ChannelTemplate.Spec + if b.Spec.ChannelTemplate != nil { + spec = *b.Spec.ChannelTemplate } return &v1alpha1.Channel{ ObjectMeta: metav1.ObjectMeta{ Namespace: b.Namespace, - GenerateName: fmt.Sprintf("%s-broker-needs-activation-", b.Name), + GenerateName: fmt.Sprintf("%s-broker-", b.Name), OwnerReferences: []metav1.OwnerReference{ *metav1.NewControllerRef(b, schema.GroupVersionKind{ Group: b.GroupVersionKind().Group, @@ -282,10 +276,10 @@ func newNeedsActivationChannel(b *v1alpha1.Broker) *v1alpha1.Channel { } } -func needsActivationLabels(b *v1alpha1.Broker) map[string]string { +func channelLabels(b *v1alpha1.Broker) map[string]string { return map[string]string{ "eventing.knative.dev/broker": b.Name, - "eventing.knative.dev/broker/needsActivation": "true", + "eventing.knative.dev/broker/everything": "true", } } @@ -320,7 +314,7 @@ func (r *reconciler) getNeedsActivationSubscription(ctx context.Context, b *v1al list := &v1alpha1.SubscriptionList{} opts := &runtimeclient.ListOptions{ Namespace: b.Namespace, - LabelSelector: labels.SelectorFromSet(needsActivationLabels(b)), + LabelSelector: labels.SelectorFromSet(channelLabels(b)), // TODO this is here because the fake client needs it. Remove this when it's no longer // needed. Raw: &metav1.ListOptions{ @@ -378,25 +372,25 @@ func newNeedsActivationSubscription(b *v1alpha1.Broker, c *v1alpha1.Channel, act } } -func (r *reconciler) reconcileKSvc(ctx context.Context, ksvc *servingv1alpha1.Service) (*servingv1alpha1.Service, error) { +func (r *reconciler) reconcileDeployment(ctx context.Context, d *v1.Deployment) (*v1.Deployment, error) { name := types.NamespacedName{ - Namespace: ksvc.Namespace, - Name: ksvc.Name, + Namespace: d.Namespace, + Name: d.Name, } - current := &servingv1alpha1.Service{} + current := &v1.Deployment{} err := r.client.Get(ctx, name, current) if k8serrors.IsNotFound(err) { - err = r.client.Create(ctx, ksvc) + err = r.client.Create(ctx, d) if err != nil { return nil, err } - return ksvc, nil + return d, nil } else if err != nil { return nil, err } - if !equality.Semantic.DeepDerivative(ksvc.Spec, current.Spec) { - current.Spec = ksvc.Spec + if !equality.Semantic.DeepDerivative(d.Spec, current.Spec) { + current.Spec = d.Spec err = r.client.Update(ctx, current) if err != nil { return nil, err @@ -405,15 +399,50 @@ func (r *reconciler) reconcileKSvc(ctx context.Context, ksvc *servingv1alpha1.Se return current, nil } -func (r *reconciler) reconcileRouter(ctx context.Context, b *v1alpha1.Broker, c *v1alpha1.Channel) (*servingv1alpha1.Service, error) { - expected, err := resources.MakeRouter(&resources.RouterArgs{ +func (r *reconciler) reconcileService(ctx context.Context, svc *corev1.Service) (*corev1.Service, error) { + name := types.NamespacedName{ + Namespace: svc.Namespace, + Name: svc.Name, + } + current := &corev1.Service{} + err := r.client.Get(ctx, name, current) + if k8serrors.IsNotFound(err) { + err = r.client.Create(ctx, svc) + if err != nil { + return nil, err + } + return svc, nil + } else if err != nil { + return nil, err + } + + // spec.clusterIP is immutable and is set on existing services. If we don't set this to the same value, we will + // encounter an error while updating. + svc.Spec.ClusterIP = current.Spec.ClusterIP + if !equality.Semantic.DeepDerivative(svc.Spec, current.Spec) { + current.Spec = svc.Spec + err = r.client.Update(ctx, current) + if err != nil { + return nil, err + } + } + return current, nil +} + +func (r *reconciler) reconcileIngressDeployment(ctx context.Context, b *v1alpha1.Broker, c *v1alpha1.Channel) (*v1.Deployment, error) { + expected, err := resources.MakeIngress(&resources.IngressArgs{ Broker: b, Image: r.routerImage, ServiceAccountName: r.routerServiceAccountName, - NeedsActivationHost: c.Status.Address.Hostname, + ChannelAddress: c.Status.Address.Hostname, }) if err != nil { return nil, err } - return r.reconcileKSvc(ctx, expected) + return r.reconcileDeployment(ctx, expected) +} + +func (r *reconciler) reconcileIngressService(ctx context.Context, b *v1alpha1.Broker) (*corev1.Service, error) { + expected := resources.MakeIngressService(b) + return r.reconcileService(ctx, expected) } diff --git a/pkg/controller/eventing/broker/resources/activator.go b/pkg/controller/eventing/broker/resources/activator.go deleted file mode 100644 index 1de0820eef1..00000000000 --- a/pkg/controller/eventing/broker/resources/activator.go +++ /dev/null @@ -1,75 +0,0 @@ -/* -Copyright 2018 The Knative Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT 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 resources - -import ( - "encoding/json" - "fmt" - - eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" - servingv1alpha1 "github.com/knative/serving/pkg/apis/serving/v1alpha1" - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime/schema" -) - -type ActivatorArgs struct { - Broker *eventingv1alpha1.Broker - Image string - ServiceAccountName string -} - -func MakeActivator(args *ActivatorArgs) (*servingv1alpha1.Service, error) { - templateJson, err := json.Marshal(args.Broker.Spec.ChannelTemplate) - if err != nil { - return nil, err - } - - return &servingv1alpha1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: args.Broker.Namespace, - Name: fmt.Sprintf("%s-broker-activator", args.Broker.Name), - OwnerReferences: []metav1.OwnerReference{ - *metav1.NewControllerRef(args.Broker, schema.GroupVersionKind{ - Group: args.Broker.GroupVersionKind().Group, - Version: args.Broker.GroupVersionKind().Version, - Kind: args.Broker.GroupVersionKind().Kind, - }), - }, - }, - Spec: servingv1alpha1.ServiceSpec{ - RunLatest: &servingv1alpha1.RunLatestType{ - Configuration: servingv1alpha1.ConfigurationSpec{ - RevisionTemplate: servingv1alpha1.RevisionTemplateSpec{ - Spec: servingv1alpha1.RevisionSpec{ - ServiceAccountName: args.ServiceAccountName, - Container: v1.Container{ - Image: args.Image, - Env: []v1.EnvVar{ - { - Name: "CHANNEL_TEMPLATE", - Value: string(templateJson), - }, - }, - }, - }, - }, - }, - }, - }, - }, nil -} diff --git a/pkg/controller/eventing/broker/resources/filter.go b/pkg/controller/eventing/broker/resources/filter.go new file mode 100644 index 00000000000..62a25a4103c --- /dev/null +++ b/pkg/controller/eventing/broker/resources/filter.go @@ -0,0 +1,107 @@ +/* +Copyright 2018 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT 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 resources + +import ( + "fmt" + appsv1 "k8s.io/api/apps/v1" + + eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +type FilterArgs struct { + Broker *eventingv1alpha1.Broker + Image string + ServiceAccountName string +} + +func MakeFilterDeployment(args *FilterArgs) (*appsv1.Deployment, error) { + return &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: args.Broker.Namespace, + Name: fmt.Sprintf("%s-broker-filter", args.Broker.Name), + OwnerReferences: []metav1.OwnerReference{ + *metav1.NewControllerRef(args.Broker, schema.GroupVersionKind{ + Group: args.Broker.GroupVersionKind().Group, + Version: args.Broker.GroupVersionKind().Version, + Kind: args.Broker.GroupVersionKind().Kind, + }), + }, + }, + Spec: appsv1.DeploymentSpec{ + Selector: &metav1.LabelSelector{ + MatchLabels: filterLabels(args.Broker), + }, + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: filterLabels(args.Broker), + }, + Spec: corev1.PodSpec{ + ServiceAccountName: args.ServiceAccountName, + Containers: []corev1.Container{ + { + Image: args.Image, + Name: "ingress", + Env: []corev1.EnvVar{ + { + Name: "BROKER", + Value: args.Broker.Name, + }, + }, + }, + }, + }, + }, + }, + }, nil +} + +func MakeFilterService(b *eventingv1alpha1.Broker) *corev1.Service { + return &corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: b.Namespace, + Name: fmt.Sprintf("%s-broker-filter", b.Name), + Labels: filterLabels(b), + OwnerReferences: []metav1.OwnerReference{ + *metav1.NewControllerRef(b, schema.GroupVersionKind{ + Group: b.GroupVersionKind().Group, + Version: b.GroupVersionKind().Version, + Kind: b.GroupVersionKind().Kind, + }), + }, + }, + Spec: corev1.ServiceSpec{ + Selector: filterLabels(b), + Ports: []corev1.ServicePort{ + { + Name: "http", + Port: 80, + }, + }, + }, + } +} + +func filterLabels(b *eventingv1alpha1.Broker) map[string]string { + return map[string]string{ + "eventing.knative.dev/broker": b.Name, + "eventing.knative.dev/broker/role": "filter", + } +} diff --git a/pkg/controller/eventing/broker/resources/ingress.go b/pkg/controller/eventing/broker/resources/ingress.go new file mode 100644 index 00000000000..d129361f55f --- /dev/null +++ b/pkg/controller/eventing/broker/resources/ingress.go @@ -0,0 +1,112 @@ +/* +Copyright 2018 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT 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 resources + +import ( + "fmt" + appsv1 "k8s.io/api/apps/v1" + + eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +type IngressArgs struct { + Broker *eventingv1alpha1.Broker + Image string + ServiceAccountName string + ChannelAddress string +} + +func MakeIngress(args *IngressArgs) (*appsv1.Deployment, error) { + return &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: args.Broker.Namespace, + Name: fmt.Sprintf("%s-broker-ingress", args.Broker.Name), + OwnerReferences: []metav1.OwnerReference{ + *metav1.NewControllerRef(args.Broker, schema.GroupVersionKind{ + Group: args.Broker.GroupVersionKind().Group, + Version: args.Broker.GroupVersionKind().Version, + Kind: args.Broker.GroupVersionKind().Kind, + }), + }, + }, + Spec: appsv1.DeploymentSpec{ + Selector: &metav1.LabelSelector{ + MatchLabels: ingressLabels(args.Broker), + }, + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: ingressLabels(args.Broker), + }, + Spec: corev1.PodSpec{ + ServiceAccountName: args.ServiceAccountName, + Containers: []corev1.Container{ + { + Image: args.Image, + Name: "ingress", + Env: []corev1.EnvVar{ + { + Name: "FILTER", + Value: "", // TODO Add one. + }, + { + Name: "CHANNEL", + Value: args.ChannelAddress, + }, + }, + }, + }, + }, + }, + }, + }, nil +} + +func MakeIngressService(b *eventingv1alpha1.Broker) *corev1.Service { + return &corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: b.Namespace, + Name: fmt.Sprintf("%s-broker", b.Name), + Labels: ingressLabels(b), + OwnerReferences: []metav1.OwnerReference{ + *metav1.NewControllerRef(b, schema.GroupVersionKind{ + Group: b.GroupVersionKind().Group, + Version: b.GroupVersionKind().Version, + Kind: b.GroupVersionKind().Kind, + }), + }, + }, + Spec: corev1.ServiceSpec{ + Selector: ingressLabels(b), + Ports: []corev1.ServicePort{ + { + Name: "http", + Port: 80, + }, + }, + }, + } +} + +func ingressLabels(b *eventingv1alpha1.Broker) map[string]string { + return map[string]string{ + "eventing.knative.dev/broker": b.Name, + "eventing.knative.dev/broker/role": "ingress", + } +} diff --git a/pkg/controller/eventing/broker/resources/router.go b/pkg/controller/eventing/broker/resources/router.go deleted file mode 100644 index baf8ac4b39c..00000000000 --- a/pkg/controller/eventing/broker/resources/router.go +++ /dev/null @@ -1,80 +0,0 @@ -/* -Copyright 2018 The Knative Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT 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 resources - -import ( - "encoding/json" - "fmt" - - eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" - servingv1alpha1 "github.com/knative/serving/pkg/apis/serving/v1alpha1" - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime/schema" -) - -type RouterArgs struct { - Broker *eventingv1alpha1.Broker - Image string - ServiceAccountName string - NeedsActivationHost string -} - -func MakeRouter(args *RouterArgs) (*servingv1alpha1.Service, error) { - selectorJson, err := json.Marshal(args.Broker.Spec.Selector) - if err != nil { - return nil, err - } - - return &servingv1alpha1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: args.Broker.Namespace, - Name: fmt.Sprintf("%s-broker", args.Broker.Name), - OwnerReferences: []metav1.OwnerReference{ - *metav1.NewControllerRef(args.Broker, schema.GroupVersionKind{ - Group: args.Broker.GroupVersionKind().Group, - Version: args.Broker.GroupVersionKind().Version, - Kind: args.Broker.GroupVersionKind().Kind, - }), - }, - }, - Spec: servingv1alpha1.ServiceSpec{ - RunLatest: &servingv1alpha1.RunLatestType{ - Configuration: servingv1alpha1.ConfigurationSpec{ - RevisionTemplate: servingv1alpha1.RevisionTemplateSpec{ - Spec: servingv1alpha1.RevisionSpec{ - ServiceAccountName: args.ServiceAccountName, - Container: v1.Container{ - Image: args.Image, - Env: []v1.EnvVar{ - { - Name: "NEEDS_ACTIVATION_HOST", - Value: args.NeedsActivationHost, - }, - { - Name: "LABEL_SELECTOR", - Value: string(selectorJson), - }, - }, - }, - }, - }, - }, - }, - }, - }, nil -} diff --git a/third_party/VENDOR-LICENSE b/third_party/VENDOR-LICENSE index fea782378a7..f2dcb874614 100644 --- a/third_party/VENDOR-LICENSE +++ b/third_party/VENDOR-LICENSE @@ -1685,6 +1685,213 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +=========================================================== +Import: github.com/knative/eventing/vendor/github.com/google/go-containerregistry + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + =========================================================== Import: github.com/knative/eventing/vendor/github.com/google/gofuzz @@ -2639,7 +2846,423 @@ SOFTWARE. =========================================================== -Import: github.com/knative/eventing/vendor/github.com/knative/pkg +Import: github.com/knative/eventing/vendor/github.com/knative/build + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + +=========================================================== +Import: github.com/knative/eventing/vendor/github.com/knative/pkg + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + +=========================================================== +Import: github.com/knative/eventing/vendor/github.com/knative/serving + Apache License Version 2.0, January 2004 From f8cca2eaa8c03568bb7de579e9d2f84703db00e2 Mon Sep 17 00:00:00 2001 From: Adam Harwayne Date: Mon, 4 Feb 2019 21:12:46 -0800 Subject: [PATCH 009/221] Initial work on the Trigger controller. --- cmd/controller/main.go | 11 +- config/500-controller.yaml | 9 + pkg/controller/eventing/broker/provider.go | 11 +- pkg/controller/eventing/broker/reconcile.go | 99 +-- pkg/controller/eventing/trigger/provider.go | 28 - pkg/controller/eventing/trigger/reconcile.go | 363 +++++++---- third_party/VENDOR-LICENSE | 623 ------------------- 7 files changed, 280 insertions(+), 864 deletions(-) diff --git a/cmd/controller/main.go b/cmd/controller/main.go index 22212fc6e6c..52661d99c5e 100644 --- a/cmd/controller/main.go +++ b/cmd/controller/main.go @@ -21,6 +21,7 @@ import ( "flag" "log" "net/http" + "os" "time" "github.com/knative/eventing/pkg/controller/eventing/trigger" @@ -123,7 +124,7 @@ func main() { // manager run it. providers := []ProvideFunc{ subscription.ProvideController, - broker.ProvideController(logger.Desugar()), + broker.ProvideController(logger.Desugar(), getRequiredEnv("INGRESS_IMAGE"), getRequiredEnv("INGRESS_SERVICE_ACCOUNT"), getRequiredEnv("FILTER_IMAGE"), getRequiredEnv("FILTER_SERVICE_ACCOUNT")), trigger.ProvideController(logger.Desugar()), } for _, provider := range providers { @@ -194,3 +195,11 @@ func getLoggingConfigOrDie() map[string]string { return cm } } + +func getRequiredEnv(envKey string) string { + val, defined := os.LookupEnv(envKey) + if !defined { + log.Fatalf("required environment variable not defined '%s'", envKey) + } + return val +} diff --git a/config/500-controller.yaml b/config/500-controller.yaml index 40da3a7be30..1c6e9336154 100644 --- a/config/500-controller.yaml +++ b/config/500-controller.yaml @@ -35,6 +35,15 @@ spec: "-logtostderr", "-stderrthreshold", "INFO" ] + env: + - name: INGRESS_IMAGE + value: github.com/knative/eventing/cmd/broker/ingress + - name: INGRESS_SERVICE_ACCOUNT + value: default + - name: FILTER_IMAGE + value: github.com/knative/eventing/cmd/broker/filter + - name: FILTER_SERVICE_ACCOUNT + value: default volumeMounts: - name: config-logging mountPath: /etc/config-logging diff --git a/pkg/controller/eventing/broker/provider.go b/pkg/controller/eventing/broker/provider.go index 8b78d982685..b3655a72ba1 100644 --- a/pkg/controller/eventing/broker/provider.go +++ b/pkg/controller/eventing/broker/provider.go @@ -44,8 +44,8 @@ type reconciler struct { logger *zap.Logger - routerImage string - routerServiceAccountName string + ingressImage string + ingressServiceAccountName string filterImage string filterServiceAccountName string } @@ -54,13 +54,18 @@ type reconciler struct { var _ reconcile.Reconciler = &reconciler{} // ProvideController returns a function that returns a Broker controller. -func ProvideController(logger *zap.Logger) func(manager.Manager) (controller.Controller, error) { +func ProvideController(logger *zap.Logger, ingressImage, ingressServiceAccount, filterImage, filterServiceAccount string) func(manager.Manager) (controller.Controller, error) { return func(mgr manager.Manager) (controller.Controller, error) { // Setup a new controller to Reconcile Brokers. c, err := controller.New(controllerAgentName, mgr, controller.Options{ Reconciler: &reconciler{ recorder: mgr.GetRecorder(controllerAgentName), logger: logger, + + ingressImage: ingressImage, + ingressServiceAccountName: ingressServiceAccount, + filterImage: filterImage, + filterServiceAccountName: filterServiceAccount, }, }) if err != nil { diff --git a/pkg/controller/eventing/broker/reconcile.go b/pkg/controller/eventing/broker/reconcile.go index 720ef29a266..8f7b1fb7f0c 100644 --- a/pkg/controller/eventing/broker/reconcile.go +++ b/pkg/controller/eventing/broker/reconcile.go @@ -27,8 +27,6 @@ import ( "github.com/knative/eventing/pkg/controller/eventing/broker/resources" - servingv1alpha1 "github.com/knative/serving/pkg/apis/serving/v1alpha1" - "github.com/knative/eventing/pkg/provisioners/gcppubsub/util/logging" "go.uber.org/zap" @@ -230,7 +228,7 @@ func (r *reconciler) getChannel(ctx context.Context, b *v1alpha1.Broker) (*v1alp list := &v1alpha1.ChannelList{} opts := &runtimeclient.ListOptions{ Namespace: b.Namespace, - LabelSelector: labels.SelectorFromSet(channelLabels(b)), + LabelSelector: labels.SelectorFromSet(ChannelLabels(b)), // TODO this is here because the fake client needs it. Remove this when it's no longer // needed. Raw: &metav1.ListOptions{ @@ -276,102 +274,13 @@ func newChannel(b *v1alpha1.Broker) *v1alpha1.Channel { } } -func channelLabels(b *v1alpha1.Broker) map[string]string { +func ChannelLabels(b *v1alpha1.Broker) map[string]string { return map[string]string{ "eventing.knative.dev/broker": b.Name, "eventing.knative.dev/broker/everything": "true", } } -func (r *reconciler) reconcileNeedsActivationSubscription(ctx context.Context, b *v1alpha1.Broker, activator *servingv1alpha1.Service, c *v1alpha1.Channel) (*v1alpha1.Subscription, error) { - expected := newNeedsActivationSubscription(b, c, activator) - - sub, err := r.getNeedsActivationSubscription(ctx, b) - // If the resource doesn't exist, we'll create it - if k8serrors.IsNotFound(err) { - sub = expected - err = r.client.Create(ctx, sub) - if err != nil { - return nil, err - } - return sub, nil - } else if err != nil { - return nil, err - } - - // Update Subscription if it has changed. - if !equality.Semantic.DeepDerivative(expected.Spec, sub.Spec) { - sub.Spec = expected.Spec - err = r.client.Update(ctx, sub) - if err != nil { - return nil, err - } - } - return sub, nil -} - -func (r *reconciler) getNeedsActivationSubscription(ctx context.Context, b *v1alpha1.Broker) (*v1alpha1.Subscription, error) { - list := &v1alpha1.SubscriptionList{} - opts := &runtimeclient.ListOptions{ - Namespace: b.Namespace, - LabelSelector: labels.SelectorFromSet(channelLabels(b)), - // TODO this is here because the fake client needs it. Remove this when it's no longer - // needed. - Raw: &metav1.ListOptions{ - TypeMeta: metav1.TypeMeta{ - APIVersion: v1alpha1.SchemeGroupVersion.String(), - Kind: "Subscription", - }, - }, - } - - err := r.client.List(ctx, opts, list) - if err != nil { - return nil, err - } - for _, sub := range list.Items { - if metav1.IsControlledBy(&sub, b) { - return &sub, nil - } - } - - return nil, k8serrors.NewNotFound(schema.GroupResource{}, "") -} - -func newNeedsActivationSubscription(b *v1alpha1.Broker, c *v1alpha1.Channel, activator *servingv1alpha1.Service) *v1alpha1.Subscription { - return &v1alpha1.Subscription{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: b.Namespace, - GenerateName: fmt.Sprintf("%s-broker-needs-activation-", b.Name), - OwnerReferences: []metav1.OwnerReference{ - *metav1.NewControllerRef(b, schema.GroupVersionKind{ - Group: b.GroupVersionKind().Group, - Version: b.GroupVersionKind().Version, - Kind: b.GroupVersionKind().Kind, - }), - }, - }, - Spec: v1alpha1.SubscriptionSpec{ - Channel: corev1.ObjectReference{ - APIVersion: c.APIVersion, - Kind: c.Kind, - Namespace: c.Namespace, - Name: c.Name, - UID: c.UID, - }, - Subscriber: &v1alpha1.SubscriberSpec{ - Ref: &corev1.ObjectReference{ - APIVersion: activator.APIVersion, - Kind: activator.Kind, - Namespace: activator.Namespace, - Name: activator.Name, - UID: activator.UID, - }, - }, - }, - } -} - func (r *reconciler) reconcileDeployment(ctx context.Context, d *v1.Deployment) (*v1.Deployment, error) { name := types.NamespacedName{ Namespace: d.Namespace, @@ -432,8 +341,8 @@ func (r *reconciler) reconcileService(ctx context.Context, svc *corev1.Service) func (r *reconciler) reconcileIngressDeployment(ctx context.Context, b *v1alpha1.Broker, c *v1alpha1.Channel) (*v1.Deployment, error) { expected, err := resources.MakeIngress(&resources.IngressArgs{ Broker: b, - Image: r.routerImage, - ServiceAccountName: r.routerServiceAccountName, + Image: r.ingressImage, + ServiceAccountName: r.ingressServiceAccountName, ChannelAddress: c.Status.Address.Hostname, }) if err != nil { diff --git a/pkg/controller/eventing/trigger/provider.go b/pkg/controller/eventing/trigger/provider.go index 316f3312766..1bd62841435 100644 --- a/pkg/controller/eventing/trigger/provider.go +++ b/pkg/controller/eventing/trigger/provider.go @@ -17,8 +17,6 @@ limitations under the License. package trigger import ( - "sync" - "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" "go.uber.org/zap" "k8s.io/client-go/dynamic" @@ -44,9 +42,6 @@ type reconciler struct { dynamicClient dynamic.Interface recorder record.EventRecorder - triggersLock sync.RWMutex - triggers map[string]map[reconcile.Request]bool - logger *zap.Logger } @@ -73,11 +68,6 @@ func ProvideController(logger *zap.Logger) func(manager.Manager) (controller.Con return nil, err } - // TODO Make this much, much more efficient. - if err = c.Watch(&source.Kind{Type: &v1alpha1.Channel{}}, &handler.EnqueueRequestsFromMapFunc{ToRequests: &mapAllTriggers{r}}); err != nil { - return nil, err - } - return c, nil } } @@ -93,21 +83,3 @@ func (r *reconciler) InjectConfig(c *rest.Config) error { r.dynamicClient, err = dynamic.NewForConfig(c) return err } - -type mapAllTriggers struct { - r *reconciler -} - -func (m *mapAllTriggers) Map(o handler.MapObject) []reconcile.Request { - m.r.triggersLock.RLock() - defer m.r.triggersLock.RUnlock() - triggersInNamespace := m.r.triggers[o.Meta.GetNamespace()] - if triggersInNamespace == nil { - return []reconcile.Request{} - } - reqs := make([]reconcile.Request, 0, len(triggersInNamespace)) - for name := range triggersInNamespace { - reqs = append(reqs, name) - } - return reqs -} diff --git a/pkg/controller/eventing/trigger/reconcile.go b/pkg/controller/eventing/trigger/reconcile.go index b993beeed1c..68433ae56f9 100644 --- a/pkg/controller/eventing/trigger/reconcile.go +++ b/pkg/controller/eventing/trigger/reconcile.go @@ -19,34 +19,26 @@ package trigger import ( "context" "fmt" - - "k8s.io/apimachinery/pkg/labels" - - "k8s.io/apimachinery/pkg/runtime/schema" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - - "github.com/knative/eventing/pkg/provisioners" - "k8s.io/apimachinery/pkg/types" - + "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" + "github.com/knative/eventing/pkg/controller" + "github.com/knative/eventing/pkg/controller/eventing/broker" "github.com/knative/eventing/pkg/provisioners/gcppubsub/util/logging" + istiov1alpha3 "github.com/knative/pkg/apis/istio/v1alpha3" "go.uber.org/zap" - k8serrors "k8s.io/apimachinery/pkg/api/errors" - - "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/equality" "k8s.io/apimachinery/pkg/api/errors" + k8serrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" runtimeclient "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/reconcile" ) const ( - finalizerName = controllerAgentName - - eventTypeKey = "eventing.knative.dev/broker/eventType" - // Name of the corev1.Events emitted from the reconciliation process triggerReconciled = "TriggerReconciled" triggerUpdateStatusFailed = "TriggerUpdateStatusFailed" @@ -96,21 +88,16 @@ func (r *reconciler) reconcile(ctx context.Context, t *v1alpha1.Trigger) error { t.Status.InitializeConditions() // 1. Verify the Broker exists. - // 2. Determine subscribers. - // 3. Look over all subscribable resources and subscribe to the correct ones. - // 4. [Do not do for the prototype] Inject a filter on every subscription. + // 2. Creates a K8s Service uniquely named for this Trigger. + // 3. Creates a VirtualService that routes the K8s Service to the Broker's filter service on an identifiable host name. + // 4. Creates a Subscription from the Broker's single Channel to this Trigger's K8s Service, with reply set to the Broker. if t.DeletionTimestamp != nil { // Everything is cleaned up by the garbage collector. - r.removeFromTriggers(t) - provisioners.RemoveFinalizer(t, finalizerName) return nil } - provisioners.AddFinalizer(t, finalizerName) - r.AddToTriggers(t) - - broker, err := r.getBroker(ctx, t) + b, err := r.getBroker(ctx, t) if err != nil { logging.FromContext(ctx).Error("Unable to get the Broker", zap.Error(err)) t.Status.MarkBrokerDoesNotExists() @@ -118,72 +105,33 @@ func (r *reconciler) reconcile(ctx context.Context, t *v1alpha1.Trigger) error { } t.Status.MarkBrokerExists() - subscribables, err := r.getRelevantSubscribables(ctx, t, broker.Spec.Selector) + c, err := r.getBrokerChannel(ctx, b) if err != nil { - logging.FromContext(ctx).Error("Unable to get relevant subscribables", zap.Error(err)) + logging.FromContext(ctx).Error("Unable to get the Broker's Channel", zap.Error(err)) return err } - err = r.subscribeAll(ctx, t, subscribables) + svc, err := r.reconcileK8sService(ctx, t) if err != nil { - logging.FromContext(ctx).Error("Unable to Subscribe", zap.Error(err)) - t.Status.MarkNotSubscribed("notSubscribed", "%v", err) + logging.FromContext(ctx).Error("Unable to reconcile the K8s Service", zap.Error(err)) return err } - t.Status.MarkSubscribed() - - return nil -} - -func (r *reconciler) AddToTriggers(t *v1alpha1.Trigger) { - name := reconcile.Request{ - NamespacedName: types.NamespacedName{ - Namespace: t.Namespace, - Name: t.Name, - }, - } - - // We will be reconciling an already existing Trigger far more often than adding a new one, so - // check with a read lock before using the write lock. - r.triggersLock.RLock() - triggersInNamespace := r.triggers[t.Namespace] - var present bool - if triggersInNamespace != nil { - _, present = triggersInNamespace[name] - } else { - present = false - } - r.triggersLock.RUnlock() - if present { - // Already present in the map. - return - } - - r.triggersLock.Lock() - triggersInNamespace = r.triggers[t.Namespace] - if triggersInNamespace == nil { - r.triggers[t.Namespace] = make(map[reconcile.Request]bool) - triggersInNamespace = r.triggers[t.Namespace] + _, err = r.reconcileVirtualService(ctx, t, svc) + if err != nil { + logging.FromContext(ctx).Error("Unable to reconcile the VirtualService", zap.Error(err)) + return err } - triggersInNamespace[name] = false - r.triggersLock.Unlock() -} -func (r *reconciler) removeFromTriggers(t *v1alpha1.Trigger) { - name := reconcile.Request{ - NamespacedName: types.NamespacedName{ - Namespace: t.Namespace, - Name: t.Name, - }, + _, err = r.subscribeToBrokerChannel(ctx, t, c, svc) + if err != nil { + logging.FromContext(ctx).Error("Unable to Subscribe", zap.Error(err)) + t.Status.MarkNotSubscribed("notSubscribed", "%v", err) + return err } + t.Status.MarkSubscribed() - r.triggersLock.Lock() - triggersInNamespace := r.triggers[t.Namespace] - if triggersInNamespace != nil { - delete(triggersInNamespace, name) - } - r.triggersLock.Unlock() + return nil } // updateStatus may in fact update the trigger's finalizers in addition to the status @@ -226,20 +174,20 @@ func (r *reconciler) updateStatus(trigger *v1alpha1.Trigger) (*v1alpha1.Trigger, } func (r *reconciler) getBroker(ctx context.Context, t *v1alpha1.Trigger) (*v1alpha1.Broker, error) { - broker := &v1alpha1.Broker{} + b := &v1alpha1.Broker{} name := types.NamespacedName{ Namespace: t.Namespace, Name: t.Spec.Broker, } - err := r.client.Get(ctx, name, broker) - return broker, err + err := r.client.Get(ctx, name, b) + return b, err } -func (r *reconciler) getRelevantSubscribables(ctx context.Context, t *v1alpha1.Trigger, selector *metav1.LabelSelector) ([]v1alpha1.Channel, error) { - selector.MatchLabels[eventTypeKey] = t.Spec.Type - - subscribables := make([]v1alpha1.Channel, 0) - opts := &client.ListOptions{ +func (r *reconciler) getBrokerChannel(ctx context.Context, b *v1alpha1.Broker) (*v1alpha1.Channel, error) { + list := &v1alpha1.ChannelList{} + opts := &runtimeclient.ListOptions{ + Namespace: b.Namespace, + LabelSelector: labels.SelectorFromSet(broker.ChannelLabels(b)), // TODO this is here because the fake client needs it. Remove this when it's no longer // needed. Raw: &metav1.ListOptions{ @@ -248,39 +196,211 @@ func (r *reconciler) getRelevantSubscribables(ctx context.Context, t *v1alpha1.T Kind: "Channel", }, }, - Namespace: t.Namespace, } - for { - list := v1alpha1.ChannelList{} - err := r.client.List(ctx, opts, &list) + + err := r.client.List(ctx, opts, list) + if err != nil { + return nil, err + } + for _, c := range list.Items { + if metav1.IsControlledBy(&c, b) { + return &c, nil + } + } + + return nil, k8serrors.NewNotFound(schema.GroupResource{}, "") +} + +func (r *reconciler) getK8sService(ctx context.Context, t *v1alpha1.Trigger) (*corev1.Service, error) { + list := &corev1.ServiceList{} + opts := &runtimeclient.ListOptions{ + Namespace: t.Namespace, + LabelSelector: labels.SelectorFromSet(k8sServiceLabels(t)), + // TODO this is here because the fake client needs it. Remove this when it's no longer + // needed. + Raw: &metav1.ListOptions{ + TypeMeta: metav1.TypeMeta{ + APIVersion: corev1.SchemeGroupVersion.String(), + Kind: "Service", + }, + }, + } + + err := r.client.List(ctx, opts, list) + if err != nil { + return nil, err + } + for _, svc := range list.Items { + if metav1.IsControlledBy(&svc, t) { + return &svc, nil + } + } + + return nil, k8serrors.NewNotFound(schema.GroupResource{}, "") +} + +func (r *reconciler) reconcileK8sService(ctx context.Context, t *v1alpha1.Trigger) (*corev1.Service, error) { + current, err := r.getK8sService(ctx, t) + + // If the resource doesn't exist, we'll create it + if k8serrors.IsNotFound(err) { + svc := newK8sService(t) + err = r.client.Create(ctx, svc) + if err != nil { + return nil, err + } + return svc, nil + } else if err != nil { + return nil, err + } + + expected := newK8sService(t) + // spec.clusterIP is immutable and is set on existing services. If we don't set this to the same value, we will + // encounter an error while updating. + expected.Spec.ClusterIP = current.Spec.ClusterIP + if !equality.Semantic.DeepDerivative(expected.Spec, current.Spec) { + current.Spec = expected.Spec + err := r.client.Update(ctx, current) if err != nil { return nil, err } - for _, s := range list.Items { - subscribables = append(subscribables, s) - if list.Continue != "" { - opts.Raw.Continue = list.Continue - } else { - return subscribables, nil - } + } + return current, nil +} + +func newK8sService(t *v1alpha1.Trigger) *corev1.Service { + return &corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: t.Namespace, + GenerateName: fmt.Sprintf("trigger-%s-", t.Name), + Labels: k8sServiceLabels(t), + OwnerReferences: []metav1.OwnerReference{ + *metav1.NewControllerRef(t, schema.GroupVersionKind{ + Group: t.GroupVersionKind().Group, + Version: t.GroupVersionKind().Version, + Kind: t.GroupVersionKind().Kind, + }), + }, + }, + Spec: corev1.ServiceSpec{ + Ports: []corev1.ServicePort{ + { + Name: "http", + Port: 80, + }, + }, + }, + } +} + +func k8sServiceLabels(t *v1alpha1.Trigger) map[string]string { + return map[string]string{ + "eventing.knative.dev/trigger": t.Name, + } +} + +func (r *reconciler) getVirtualService(ctx context.Context, t *v1alpha1.Trigger) (*istiov1alpha3.VirtualService, error) { + list := &istiov1alpha3.VirtualServiceList{} + opts := &runtimeclient.ListOptions{ + Namespace: t.Namespace, + LabelSelector: labels.SelectorFromSet(virtualServiceLabels(t)), + // TODO this is here because the fake client needs it. Remove this when it's no longer + // needed. + Raw: &metav1.ListOptions{ + TypeMeta: metav1.TypeMeta{ + APIVersion: istiov1alpha3.SchemeGroupVersion.String(), + Kind: "VirtualService", + }, + }, + } + + err := r.client.List(ctx, opts, list) + if err != nil { + return nil, err + } + for _, vs := range list.Items { + if metav1.IsControlledBy(&vs, t) { + return &vs, nil } } + + return nil, k8serrors.NewNotFound(schema.GroupResource{}, "") } -func (r *reconciler) subscribeAll(ctx context.Context, t *v1alpha1.Trigger, subscribables []v1alpha1.Channel) error { - for _, subscribable := range subscribables { - _, err := r.subscribe(ctx, t, &subscribable) +func (r *reconciler) reconcileVirtualService(ctx context.Context, t *v1alpha1.Trigger, svc *corev1.Service) (*istiov1alpha3.VirtualService, error) { + virtualService, err := r.getVirtualService(ctx, t) + + // If the resource doesn't exist, we'll create it + if k8serrors.IsNotFound(err) { + virtualService = newVirtualService(t, svc) + err = r.client.Create(ctx, virtualService) if err != nil { - return err + return nil, err } + return virtualService, nil + } else if err != nil { + return nil, err } - return nil + + expected := newVirtualService(t, svc) + if !equality.Semantic.DeepDerivative(expected.Spec, virtualService.Spec) { + virtualService.Spec = expected.Spec + err := r.client.Update(ctx, virtualService) + if err != nil { + return nil, err + } + } + return virtualService, nil } -func (r *reconciler) subscribe(ctx context.Context, t *v1alpha1.Trigger, subscribable *v1alpha1.Channel) (*v1alpha1.Subscription, error) { - expected := makeSubscription(t, subscribable) +func newVirtualService(t *v1alpha1.Trigger, svc *corev1.Service) *istiov1alpha3.VirtualService { + // TODO Make this work with endings other than cluster.local + destinationHost := fmt.Sprintf("%s-broker-filter.%s.svc.cluster.local", t.Spec.Broker, t.Namespace) + return &istiov1alpha3.VirtualService{ + ObjectMeta: metav1.ObjectMeta{ + GenerateName: fmt.Sprintf("%s-", t.Name), + Namespace: t.Namespace, + Labels: virtualServiceLabels(t), + OwnerReferences: []metav1.OwnerReference{ + *metav1.NewControllerRef(t, schema.GroupVersionKind{ + Group: t.GroupVersionKind().Group, + Version: t.GroupVersionKind().Version, + Kind: t.GroupVersionKind().Kind, + }), + }, + }, + Spec: istiov1alpha3.VirtualServiceSpec{ + Hosts: []string{ + controller.ServiceHostName(svc.Name, svc.Namespace), + }, + Http: []istiov1alpha3.HTTPRoute{{ + Rewrite: &istiov1alpha3.HTTPRewrite{ + // Never really used, so cluster.local should be a good enough ending everywhere. + Authority: fmt.Sprintf("%s.%s.triggers.cluster.local", t.Name, t.Namespace), + }, + Route: []istiov1alpha3.DestinationWeight{{ + Destination: istiov1alpha3.Destination{ + Host: destinationHost, + Port: istiov1alpha3.PortSelector{ + Number: 80, + }, + }}, + }}, + }, + }, + } +} + +func virtualServiceLabels(t *v1alpha1.Trigger) map[string]string { + return map[string]string{ + "eventing.knative.dev/trigger": t.Name, + } +} + +func (r *reconciler) subscribeToBrokerChannel(ctx context.Context, t *v1alpha1.Trigger, c *v1alpha1.Channel, svc *corev1.Service) (*v1alpha1.Subscription, error) { + expected := makeSubscription(t, c, svc) - sub, err := r.getSubscription(ctx, t, subscribable) + sub, err := r.getSubscription(ctx, t, c) // If the resource doesn't exist, we'll create it if k8serrors.IsNotFound(err) { sub = expected @@ -304,7 +424,7 @@ func (r *reconciler) subscribe(ctx context.Context, t *v1alpha1.Trigger, subscri return sub, nil } -func (r *reconciler) getSubscription(ctx context.Context, t *v1alpha1.Trigger, subscribable *v1alpha1.Channel) (*v1alpha1.Subscription, error) { +func (r *reconciler) getSubscription(ctx context.Context, t *v1alpha1.Trigger, c *v1alpha1.Channel) (*v1alpha1.Subscription, error) { list := &v1alpha1.SubscriptionList{} opts := &runtimeclient.ListOptions{ Namespace: t.Namespace, @@ -332,7 +452,7 @@ func (r *reconciler) getSubscription(ctx context.Context, t *v1alpha1.Trigger, s return nil, k8serrors.NewNotFound(schema.GroupResource{}, "") } -func makeSubscription(t *v1alpha1.Trigger, subscribable *v1alpha1.Channel) *v1alpha1.Subscription { +func makeSubscription(t *v1alpha1.Trigger, c *v1alpha1.Channel, svc *corev1.Service) *v1alpha1.Subscription { return &v1alpha1.Subscription{ ObjectMeta: metav1.ObjectMeta{ Namespace: t.Namespace, @@ -348,12 +468,27 @@ func makeSubscription(t *v1alpha1.Trigger, subscribable *v1alpha1.Channel) *v1al }, Spec: v1alpha1.SubscriptionSpec{ Channel: corev1.ObjectReference{ - APIVersion: subscribable.APIVersion, - Kind: subscribable.Kind, - Namespace: subscribable.Namespace, - Name: subscribable.Name, + APIVersion: c.APIVersion, + Kind: c.Kind, + Namespace: c.Namespace, + Name: c.Name, + }, + Subscriber: &v1alpha1.SubscriberSpec{ + Ref: &corev1.ObjectReference{ + APIVersion: svc.APIVersion, + Kind: svc.Kind, + Namespace: svc.Namespace, + Name: svc.Name, + }, + }, + Reply: &v1alpha1.ReplyStrategy{ + Channel: &corev1.ObjectReference{ + APIVersion: c.APIVersion, + Kind: c.Kind, + Namespace: c.Namespace, + Name: c.Name, + }, }, - Subscriber: t.Spec.Subscriber, }, } } diff --git a/third_party/VENDOR-LICENSE b/third_party/VENDOR-LICENSE index f2dcb874614..fea782378a7 100644 --- a/third_party/VENDOR-LICENSE +++ b/third_party/VENDOR-LICENSE @@ -1685,213 +1685,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -=========================================================== -Import: github.com/knative/eventing/vendor/github.com/google/go-containerregistry - - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - =========================================================== Import: github.com/knative/eventing/vendor/github.com/google/gofuzz @@ -2845,214 +2638,6 @@ SOFTWARE. -=========================================================== -Import: github.com/knative/eventing/vendor/github.com/knative/build - - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - - =========================================================== Import: github.com/knative/eventing/vendor/github.com/knative/pkg @@ -3260,214 +2845,6 @@ Import: github.com/knative/eventing/vendor/github.com/knative/pkg -=========================================================== -Import: github.com/knative/eventing/vendor/github.com/knative/serving - - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - - =========================================================== Import: github.com/knative/eventing/vendor/github.com/markbates/inflect From d7ebdcba67d6dca906c44b1644dc07d2a7fb6646 Mon Sep 17 00:00:00 2001 From: Adam Harwayne Date: Mon, 4 Feb 2019 22:50:29 -0800 Subject: [PATCH 010/221] Add simple mains. --- cmd/broker/filter/kodata/HEAD | 1 + cmd/broker/filter/kodata/LICENSE | 1 + cmd/broker/filter/kodata/VENDOR-LICENSE | 1 + cmd/broker/filter/main.go | 67 +++++++ cmd/broker/ingress/kodata/HEAD | 1 + cmd/broker/ingress/kodata/LICENSE | 1 + cmd/broker/ingress/kodata/VENDOR-LICENSE | 1 + cmd/broker/ingress/main.go | 142 +++++++++++++ pkg/apis/eventing/v1alpha1/trigger_types.go | 2 + pkg/broker/filter.go | 110 +++++++++++ pkg/broker/filter_test.go | 187 ++++++++++++++++++ .../eventing/trigger/resources/activator.go | 75 ------- .../eventing/trigger/resources/router.go | 80 -------- 13 files changed, 514 insertions(+), 155 deletions(-) create mode 120000 cmd/broker/filter/kodata/HEAD create mode 120000 cmd/broker/filter/kodata/LICENSE create mode 120000 cmd/broker/filter/kodata/VENDOR-LICENSE create mode 100644 cmd/broker/filter/main.go create mode 120000 cmd/broker/ingress/kodata/HEAD create mode 120000 cmd/broker/ingress/kodata/LICENSE create mode 120000 cmd/broker/ingress/kodata/VENDOR-LICENSE create mode 100644 cmd/broker/ingress/main.go create mode 100644 pkg/broker/filter.go create mode 100644 pkg/broker/filter_test.go delete mode 100644 pkg/controller/eventing/trigger/resources/activator.go delete mode 100644 pkg/controller/eventing/trigger/resources/router.go diff --git a/cmd/broker/filter/kodata/HEAD b/cmd/broker/filter/kodata/HEAD new file mode 120000 index 00000000000..481bd4eff49 --- /dev/null +++ b/cmd/broker/filter/kodata/HEAD @@ -0,0 +1 @@ +../../../../.git/HEAD \ No newline at end of file diff --git a/cmd/broker/filter/kodata/LICENSE b/cmd/broker/filter/kodata/LICENSE new file mode 120000 index 00000000000..14776154326 --- /dev/null +++ b/cmd/broker/filter/kodata/LICENSE @@ -0,0 +1 @@ +../../../../LICENSE \ No newline at end of file diff --git a/cmd/broker/filter/kodata/VENDOR-LICENSE b/cmd/broker/filter/kodata/VENDOR-LICENSE new file mode 120000 index 00000000000..7322c09d957 --- /dev/null +++ b/cmd/broker/filter/kodata/VENDOR-LICENSE @@ -0,0 +1 @@ +../../../../third_party/VENDOR-LICENSE \ No newline at end of file diff --git a/cmd/broker/filter/main.go b/cmd/broker/filter/main.go new file mode 100644 index 00000000000..a8f2f8536a8 --- /dev/null +++ b/cmd/broker/filter/main.go @@ -0,0 +1,67 @@ +/* + * Copyright 2018 The Knative Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 main + +import ( + "flag" + eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" + "github.com/knative/eventing/pkg/broker" + "github.com/knative/eventing/pkg/provisioners" + "github.com/knative/pkg/signals" + "go.uber.org/zap" + "sigs.k8s.io/controller-runtime/pkg/client/config" + "sigs.k8s.io/controller-runtime/pkg/manager" +) + +func main() { + logConfig := provisioners.NewLoggingConfig() + logger := provisioners.NewProvisionerLoggerFromConfig(logConfig).Desugar() + defer logger.Sync() + + flag.Parse() + + logger.Info("Starting...") + + mgr, err := manager.New(config.GetConfigOrDie(), manager.Options{}) + if err != nil { + logger.Fatal("Error starting up.", zap.Error(err)) + } + + // Add custom types to this array to get them into the manager's scheme. + eventingv1alpha1.AddToScheme(mgr.GetScheme()) + + // We are running both the receiver (takes messages in from the cluster and writes them to + // PubSub) and the dispatcher (takes messages in PubSub and sends them in cluster) in this + // binary. + + _, runnable := broker.New(logger, mgr.GetClient()) + err = mgr.Add(runnable) + if err != nil { + logger.Fatal("Unable to start the receivers runnable", zap.Error(err), zap.Any("runnable", runnable)) + } + + // set up signals so we handle the first shutdown signal gracefully + stopCh := signals.SetupSignalHandler() + + // Start blocks forever. + logger.Info("Manager starting...") + err = mgr.Start(stopCh) + if err != nil { + logger.Fatal("Manager.Start() returned an error", zap.Error(err)) + } +} + diff --git a/cmd/broker/ingress/kodata/HEAD b/cmd/broker/ingress/kodata/HEAD new file mode 120000 index 00000000000..481bd4eff49 --- /dev/null +++ b/cmd/broker/ingress/kodata/HEAD @@ -0,0 +1 @@ +../../../../.git/HEAD \ No newline at end of file diff --git a/cmd/broker/ingress/kodata/LICENSE b/cmd/broker/ingress/kodata/LICENSE new file mode 120000 index 00000000000..14776154326 --- /dev/null +++ b/cmd/broker/ingress/kodata/LICENSE @@ -0,0 +1 @@ +../../../../LICENSE \ No newline at end of file diff --git a/cmd/broker/ingress/kodata/VENDOR-LICENSE b/cmd/broker/ingress/kodata/VENDOR-LICENSE new file mode 120000 index 00000000000..7322c09d957 --- /dev/null +++ b/cmd/broker/ingress/kodata/VENDOR-LICENSE @@ -0,0 +1 @@ +../../../../third_party/VENDOR-LICENSE \ No newline at end of file diff --git a/cmd/broker/ingress/main.go b/cmd/broker/ingress/main.go new file mode 100644 index 00000000000..865d07db82e --- /dev/null +++ b/cmd/broker/ingress/main.go @@ -0,0 +1,142 @@ +/* + * Copyright 2018 The Knative Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 main + +import ( + "context" + "flag" + "golang.org/x/sync/errgroup" + "log" + "net/http" + "os" + "time" + + eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" + "github.com/knative/eventing/pkg/provisioners" + "github.com/knative/pkg/signals" + "go.uber.org/zap" + "sigs.k8s.io/controller-runtime/pkg/client/config" + "sigs.k8s.io/controller-runtime/pkg/manager" +) + + +var ( + readTimeout = 1 * time.Minute + writeTimeout = 1 * time.Minute +) + +func main() { + logConfig := provisioners.NewLoggingConfig() + logger := provisioners.NewProvisionerLoggerFromConfig(logConfig).Desugar() + defer logger.Sync() + flag.Parse() + + logger.Info("Starting...") + + mgr, err := manager.New(config.GetConfigOrDie(), manager.Options{}) + if err != nil { + logger.Fatal("Error starting up.", zap.Error(err)) + } + + // Add custom types to this array to get them into the manager's scheme. + err = eventingv1alpha1.AddToScheme(mgr.GetScheme()) + if err != nil { + logger.Fatal("Unable to add scheme", zap.Error(err)) + } + + + c := getRequiredEnv("CHANNEL") + + h := NewHandler(logger, c) + + s := &http.Server{ + Addr: ":8080", + Handler: h, + ErrorLog: zap.NewStdLog(logger), + ReadTimeout: readTimeout, + WriteTimeout: writeTimeout, + } + + // Start both the manager (which notices ConfigMap changes) and the HTTP server. + var g errgroup.Group + g.Go(func() error { + // set up signals so we handle the first shutdown signal gracefully + stopCh := signals.SetupSignalHandler() + // Start blocks forever, so run it in a goroutine. + return mgr.Start(stopCh) + }) + logger.Info("Ingress Listening...", zap.String("Address", s.Addr)) + g.Go(s.ListenAndServe) + err = g.Wait() + if err != nil { + logger.Error("HTTP server failed.", zap.Error(err)) + } + + ctx, cancel := context.WithTimeout(context.Background(), writeTimeout) + defer cancel() + s.Shutdown(ctx) +} + +func getRequiredEnv(envKey string) string { + val, defined := os.LookupEnv(envKey) + if !defined { + log.Fatalf("required environment variable not defined '%s'", envKey) + } + return val +} + +// http.Handler that takes a single request in and fans it out to N other servers. +type Handler struct { + receiver *provisioners.MessageReceiver + dispatcher *provisioners.MessageDispatcher + destination string + + logger *zap.Logger +} + +// NewHandler creates a new fanout.Handler. +func NewHandler(logger *zap.Logger, destination string) *Handler { + handler := &Handler{ + logger: logger, + dispatcher: provisioners.NewMessageDispatcher(logger.Sugar()), + destination: destination, + } + // The receiver function needs to point back at the handler itself, so set it up after + // initialization. + handler.receiver = provisioners.NewMessageReceiver(createReceiverFunction(handler), logger.Sugar()) + + return handler +} + +func createReceiverFunction(f *Handler) func(provisioners.ChannelReference, *provisioners.Message) error { + return func(_ provisioners.ChannelReference, m *provisioners.Message) error { + // TODO Filter. + return f.dispatch(m) + } +} + +func (f *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + f.receiver.HandleRequest(w, r) +} + +// dispatch takes the request, fans it out to each subscription in f.config. If all the fanned out +// requests return successfully, then return nil. Else, return an error. +func (f *Handler) dispatch(msg *provisioners.Message) error { + return f.dispatcher.DispatchMessage(msg, f.destination, "", provisioners.DispatchDefaults{}) +} + + diff --git a/pkg/apis/eventing/v1alpha1/trigger_types.go b/pkg/apis/eventing/v1alpha1/trigger_types.go index e6dc53bb9a8..47d1ab5f5fe 100644 --- a/pkg/apis/eventing/v1alpha1/trigger_types.go +++ b/pkg/apis/eventing/v1alpha1/trigger_types.go @@ -73,6 +73,8 @@ type TriggerStatus struct { // +patchMergeKey=type // +patchStrategy=merge Conditions duckv1alpha1.Conditions `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"` + + SubscriberURI string `json:"subscriberURI,omitempty"` } const ( diff --git a/pkg/broker/filter.go b/pkg/broker/filter.go new file mode 100644 index 00000000000..cb542a2e060 --- /dev/null +++ b/pkg/broker/filter.go @@ -0,0 +1,110 @@ +/* + * Copyright 2018 The Knative Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 broker + +import ( + "context" + "errors" + + eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" + "github.com/knative/eventing/pkg/provisioners" + "github.com/knative/eventing/pkg/provisioners/gcppubsub/util/logging" + "go.uber.org/zap" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/manager" +) + +const ( + Any = "Any" +) + +// Receiver parses Cloud Events and sends them to GCP PubSub. +type Receiver struct { + logger *zap.Logger + client client.Client + + dispatcher provisioners.Dispatcher +} + +// New creates a new Receiver and its associated MessageReceiver. The caller is responsible for +// Start()ing the returned MessageReceiver. +func New(logger *zap.Logger, client client.Client) (*Receiver, manager.Runnable) { + r := &Receiver{ + logger: logger, + client: client, + dispatcher: provisioners.NewMessageDispatcher(logger.Sugar()), + } + return r, r.newMessageReceiver() +} + +func (r *Receiver) newMessageReceiver() *provisioners.MessageReceiver { + return provisioners.NewMessageReceiver(r.sendEventToTopic, r.logger.Sugar()) +} + +// sendEventToTopic sends a message to the Cloud Pub/Sub Topic backing the Channel. +func (r *Receiver) sendEventToTopic(channel provisioners.ChannelReference, message *provisioners.Message) error { + r.logger.Debug("received message") + ctx := context.Background() + + t, err := r.getTrigger(ctx, channel) + if err != nil { + logging.FromContext(ctx).Info("Unable to get the Trigger", zap.Error(err), zap.Any("channelRef", channel)) + return err + } + + subscriberURI := t.Status.SubscriberURI + if subscriberURI == "" { + logging.FromContext(ctx).Error("Unable to read subscriberURI") + return errors.New("unable to read subscriberURI") + } + + if !shouldSendMessage(t.Spec, message) { + logging.FromContext(ctx).Debug("Message did not pass filter") + return nil + } + + err = r.dispatcher.DispatchMessage(message, subscriberURI, "", provisioners.DispatchDefaults{}) + if err != nil { + logging.FromContext(ctx).Info("Failed to dispatch message", zap.Error(err)) + return err + } + logging.FromContext(ctx).Debug("Successfully sent message") + return nil +} + +func (r *Receiver) getTrigger(ctx context.Context, ref provisioners.ChannelReference) (*eventingv1alpha1.Trigger, error) { + t := &eventingv1alpha1.Trigger{} + err := r.client.Get(ctx, + types.NamespacedName{ + Namespace: ref.Namespace, + Name: ref.Name, + }, + t) + return t, err +} + +func shouldSendMessage(t eventingv1alpha1.TriggerSpec, m *provisioners.Message) bool { + // TODO More filtering! + if t.Type != Any && t.Type != m.Headers["type"] { + return false + } + if t.Source != "" && t.Source != m.Headers["source"] { + return false + } + return true +} diff --git a/pkg/broker/filter_test.go b/pkg/broker/filter_test.go new file mode 100644 index 00000000000..77d9b0d0923 --- /dev/null +++ b/pkg/broker/filter_test.go @@ -0,0 +1,187 @@ +/* + * Copyright 2018 The Knative Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 broker + +import ( + "context" + "errors" + "net/http/httptest" + "strings" + "testing" + + "github.com/knative/eventing/pkg/provisioners/gcppubsub/util" + + eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" + "k8s.io/client-go/kubernetes/scheme" + + "github.com/knative/eventing/pkg/provisioners/gcppubsub/util/fakepubsub" + "go.uber.org/zap" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + + "sigs.k8s.io/controller-runtime/pkg/client/fake" + + "github.com/knative/eventing/pkg/provisioners/gcppubsub/util/testcreds" +) + +const ( + validMessage = `{ + "cloudEventsVersion" : "0.1", + "eventType" : "com.example.someevent", + "eventTypeVersion" : "1.0", + "source" : "/mycontext", + "eventID" : "A234-1234-1234", + "eventTime" : "2018-04-05T17:31:00Z", + "extensions" : { + "comExampleExtension" : "value" + }, + "contentType" : "text/xml", + "data" : "" +}` +) + +func init() { + // Add types to scheme. + eventingv1alpha1.AddToScheme(scheme.Scheme) +} + +func TestReceiver(t *testing.T) { + testCases := map[string]struct { + initialState []runtime.Object + pubSubData fakepubsub.CreatorData + expectedErr bool + }{ + "can't get channel": { + initialState: []runtime.Object{ + testcreds.MakeSecretWithInvalidCreds(), + }, + expectedErr: true, + }, + "can't read status": { + initialState: []runtime.Object{ + testcreds.MakeSecretWithInvalidCreds(), + makeChannelWithBadStatus(), + }, + expectedErr: true, + }, + "blank status": { + initialState: []runtime.Object{ + testcreds.MakeSecretWithInvalidCreds(), + makeChannelWithBlankStatus(), + }, + expectedErr: true, + }, + "credential fails": { + initialState: []runtime.Object{ + testcreds.MakeSecretWithInvalidCreds(), + makeChannel(), + }, + expectedErr: true, + }, + "PubSub client fails": { + initialState: []runtime.Object{ + testcreds.MakeSecretWithCreds(), + makeChannel(), + }, + pubSubData: fakepubsub.CreatorData{ + ClientCreateErr: errors.New("testInducedError"), + }, + expectedErr: true, + }, + "Publish fails": { + initialState: []runtime.Object{ + testcreds.MakeSecretWithCreds(), + makeChannel(), + }, + pubSubData: fakepubsub.CreatorData{ + ClientData: fakepubsub.ClientData{ + TopicData: fakepubsub.TopicData{ + Publish: fakepubsub.PublishResultData{ + Err: errors.New("testInducedError"), + }, + }, + }, + }, + expectedErr: true, + }, + "Publish succeeds": { + initialState: []runtime.Object{ + testcreds.MakeSecretWithCreds(), + makeChannel(), + }, + }, + } + for n, tc := range testCases { + t.Run(n, func(t *testing.T) { + mr, _ := New( + zap.NewNop(), + fake.NewFakeClient(tc.initialState...), + fakepubsub.Creator(tc.pubSubData)) + resp := httptest.NewRecorder() + req := httptest.NewRequest("POST", "/", strings.NewReader(validMessage)) + req.Host = "test-channel.test-namespace.channels.cluster.local" + mr.newMessageReceiver().HandleRequest(resp, req) + if tc.expectedErr { + if resp.Result().StatusCode >= 200 && resp.Result().StatusCode < 300 { + t.Errorf("Expected an error. Actual: %v", resp.Result()) + } + } else { + if resp.Result().StatusCode < 200 || resp.Result().StatusCode >= 300 { + t.Errorf("Expected success. Actual: %v", resp.Result()) + } + } + }) + } +} + +func makeChannel() *eventingv1alpha1.Channel { + c := &eventingv1alpha1.Channel{ + TypeMeta: v1.TypeMeta{ + APIVersion: "eventing.knative.dev/v1alpha1", + Kind: "Channel", + }, + ObjectMeta: v1.ObjectMeta{ + Namespace: "test-namespace", + Name: "test-channel", + }, + } + pcs := &util.GcpPubSubChannelStatus{ + GCPProject: "project", + Secret: testcreds.Secret, + SecretKey: testcreds.SecretKey, + } + if err := util.SetInternalStatus(context.Background(), c, pcs); err != nil { + panic(err) + } + return c +} + +func makeChannelWithBlankStatus() *eventingv1alpha1.Channel { + c := makeChannel() + c.Status = eventingv1alpha1.ChannelStatus{} + return c +} + +func makeChannelWithBadStatus() *eventingv1alpha1.Channel { + c := makeChannel() + c.Status.Internal = &runtime.RawExtension{ + // SecretKey must be a string, not an integer, so this will fail during json.Unmarshal. + Raw: []byte(`{"secretKey": 123}`), + } + return c +} diff --git a/pkg/controller/eventing/trigger/resources/activator.go b/pkg/controller/eventing/trigger/resources/activator.go deleted file mode 100644 index 1de0820eef1..00000000000 --- a/pkg/controller/eventing/trigger/resources/activator.go +++ /dev/null @@ -1,75 +0,0 @@ -/* -Copyright 2018 The Knative Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT 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 resources - -import ( - "encoding/json" - "fmt" - - eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" - servingv1alpha1 "github.com/knative/serving/pkg/apis/serving/v1alpha1" - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime/schema" -) - -type ActivatorArgs struct { - Broker *eventingv1alpha1.Broker - Image string - ServiceAccountName string -} - -func MakeActivator(args *ActivatorArgs) (*servingv1alpha1.Service, error) { - templateJson, err := json.Marshal(args.Broker.Spec.ChannelTemplate) - if err != nil { - return nil, err - } - - return &servingv1alpha1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: args.Broker.Namespace, - Name: fmt.Sprintf("%s-broker-activator", args.Broker.Name), - OwnerReferences: []metav1.OwnerReference{ - *metav1.NewControllerRef(args.Broker, schema.GroupVersionKind{ - Group: args.Broker.GroupVersionKind().Group, - Version: args.Broker.GroupVersionKind().Version, - Kind: args.Broker.GroupVersionKind().Kind, - }), - }, - }, - Spec: servingv1alpha1.ServiceSpec{ - RunLatest: &servingv1alpha1.RunLatestType{ - Configuration: servingv1alpha1.ConfigurationSpec{ - RevisionTemplate: servingv1alpha1.RevisionTemplateSpec{ - Spec: servingv1alpha1.RevisionSpec{ - ServiceAccountName: args.ServiceAccountName, - Container: v1.Container{ - Image: args.Image, - Env: []v1.EnvVar{ - { - Name: "CHANNEL_TEMPLATE", - Value: string(templateJson), - }, - }, - }, - }, - }, - }, - }, - }, - }, nil -} diff --git a/pkg/controller/eventing/trigger/resources/router.go b/pkg/controller/eventing/trigger/resources/router.go deleted file mode 100644 index baf8ac4b39c..00000000000 --- a/pkg/controller/eventing/trigger/resources/router.go +++ /dev/null @@ -1,80 +0,0 @@ -/* -Copyright 2018 The Knative Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT 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 resources - -import ( - "encoding/json" - "fmt" - - eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" - servingv1alpha1 "github.com/knative/serving/pkg/apis/serving/v1alpha1" - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime/schema" -) - -type RouterArgs struct { - Broker *eventingv1alpha1.Broker - Image string - ServiceAccountName string - NeedsActivationHost string -} - -func MakeRouter(args *RouterArgs) (*servingv1alpha1.Service, error) { - selectorJson, err := json.Marshal(args.Broker.Spec.Selector) - if err != nil { - return nil, err - } - - return &servingv1alpha1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: args.Broker.Namespace, - Name: fmt.Sprintf("%s-broker", args.Broker.Name), - OwnerReferences: []metav1.OwnerReference{ - *metav1.NewControllerRef(args.Broker, schema.GroupVersionKind{ - Group: args.Broker.GroupVersionKind().Group, - Version: args.Broker.GroupVersionKind().Version, - Kind: args.Broker.GroupVersionKind().Kind, - }), - }, - }, - Spec: servingv1alpha1.ServiceSpec{ - RunLatest: &servingv1alpha1.RunLatestType{ - Configuration: servingv1alpha1.ConfigurationSpec{ - RevisionTemplate: servingv1alpha1.RevisionTemplateSpec{ - Spec: servingv1alpha1.RevisionSpec{ - ServiceAccountName: args.ServiceAccountName, - Container: v1.Container{ - Image: args.Image, - Env: []v1.EnvVar{ - { - Name: "NEEDS_ACTIVATION_HOST", - Value: args.NeedsActivationHost, - }, - { - Name: "LABEL_SELECTOR", - Value: string(selectorJson), - }, - }, - }, - }, - }, - }, - }, - }, - }, nil -} From c5f7a837f12d9ec4b0906f5677826e1b267e95b5 Mon Sep 17 00:00:00 2001 From: Adam Harwayne Date: Mon, 4 Feb 2019 23:07:52 -0800 Subject: [PATCH 011/221] Small fixes, still not working. --- b.yaml | 11 +++++++++++ pkg/controller/eventing/broker/reconcile.go | 6 +++--- .../eventing/broker/resources/filter.go | 12 ++++++------ .../eventing/broker/resources/ingress.go | 12 ++++++------ pkg/controller/eventing/trigger/reconcile.go | 18 +++++++++--------- 5 files changed, 35 insertions(+), 24 deletions(-) create mode 100644 b.yaml diff --git a/b.yaml b/b.yaml new file mode 100644 index 00000000000..595b6eb20ac --- /dev/null +++ b/b.yaml @@ -0,0 +1,11 @@ +apiVersion: eventing.knative.dev/v1alpha1 +kind: Broker +metadata: + name: default +spec: + channelTemplate: + provisioner: + apiVersion: eventing.knative.dev/v1alpha1 + kind: ClusterChannelProvisioner + name: gcp-pubsub + diff --git a/pkg/controller/eventing/broker/reconcile.go b/pkg/controller/eventing/broker/reconcile.go index 8f7b1fb7f0c..4a380fc0bfe 100644 --- a/pkg/controller/eventing/broker/reconcile.go +++ b/pkg/controller/eventing/broker/reconcile.go @@ -264,9 +264,9 @@ func newChannel(b *v1alpha1.Broker) *v1alpha1.Channel { GenerateName: fmt.Sprintf("%s-broker-", b.Name), OwnerReferences: []metav1.OwnerReference{ *metav1.NewControllerRef(b, schema.GroupVersionKind{ - Group: b.GroupVersionKind().Group, - Version: b.GroupVersionKind().Version, - Kind: b.GroupVersionKind().Kind, + Group: v1alpha1.SchemeGroupVersion.Group, + Version: v1alpha1.SchemeGroupVersion.Version, + Kind: "Broker", }), }, }, diff --git a/pkg/controller/eventing/broker/resources/filter.go b/pkg/controller/eventing/broker/resources/filter.go index 62a25a4103c..8e3aad3b12b 100644 --- a/pkg/controller/eventing/broker/resources/filter.go +++ b/pkg/controller/eventing/broker/resources/filter.go @@ -39,9 +39,9 @@ func MakeFilterDeployment(args *FilterArgs) (*appsv1.Deployment, error) { Name: fmt.Sprintf("%s-broker-filter", args.Broker.Name), OwnerReferences: []metav1.OwnerReference{ *metav1.NewControllerRef(args.Broker, schema.GroupVersionKind{ - Group: args.Broker.GroupVersionKind().Group, - Version: args.Broker.GroupVersionKind().Version, - Kind: args.Broker.GroupVersionKind().Kind, + Group: eventingv1alpha1.SchemeGroupVersion.Group, + Version: eventingv1alpha1.SchemeGroupVersion.Version, + Kind: "Broker", }), }, }, @@ -81,9 +81,9 @@ func MakeFilterService(b *eventingv1alpha1.Broker) *corev1.Service { Labels: filterLabels(b), OwnerReferences: []metav1.OwnerReference{ *metav1.NewControllerRef(b, schema.GroupVersionKind{ - Group: b.GroupVersionKind().Group, - Version: b.GroupVersionKind().Version, - Kind: b.GroupVersionKind().Kind, + Group: eventingv1alpha1.SchemeGroupVersion.Group, + Version: eventingv1alpha1.SchemeGroupVersion.Version, + Kind: "Broker", }), }, }, diff --git a/pkg/controller/eventing/broker/resources/ingress.go b/pkg/controller/eventing/broker/resources/ingress.go index d129361f55f..33777f28c21 100644 --- a/pkg/controller/eventing/broker/resources/ingress.go +++ b/pkg/controller/eventing/broker/resources/ingress.go @@ -40,9 +40,9 @@ func MakeIngress(args *IngressArgs) (*appsv1.Deployment, error) { Name: fmt.Sprintf("%s-broker-ingress", args.Broker.Name), OwnerReferences: []metav1.OwnerReference{ *metav1.NewControllerRef(args.Broker, schema.GroupVersionKind{ - Group: args.Broker.GroupVersionKind().Group, - Version: args.Broker.GroupVersionKind().Version, - Kind: args.Broker.GroupVersionKind().Kind, + Group: eventingv1alpha1.SchemeGroupVersion.Group, + Version: eventingv1alpha1.SchemeGroupVersion.Version, + Kind: "Broker", }), }, }, @@ -86,9 +86,9 @@ func MakeIngressService(b *eventingv1alpha1.Broker) *corev1.Service { Labels: ingressLabels(b), OwnerReferences: []metav1.OwnerReference{ *metav1.NewControllerRef(b, schema.GroupVersionKind{ - Group: b.GroupVersionKind().Group, - Version: b.GroupVersionKind().Version, - Kind: b.GroupVersionKind().Kind, + Group: eventingv1alpha1.SchemeGroupVersion.Group, + Version: eventingv1alpha1.SchemeGroupVersion.Version, + Kind: "Broker", }), }, }, diff --git a/pkg/controller/eventing/trigger/reconcile.go b/pkg/controller/eventing/trigger/reconcile.go index 68433ae56f9..b1805336922 100644 --- a/pkg/controller/eventing/trigger/reconcile.go +++ b/pkg/controller/eventing/trigger/reconcile.go @@ -276,9 +276,9 @@ func newK8sService(t *v1alpha1.Trigger) *corev1.Service { Labels: k8sServiceLabels(t), OwnerReferences: []metav1.OwnerReference{ *metav1.NewControllerRef(t, schema.GroupVersionKind{ - Group: t.GroupVersionKind().Group, - Version: t.GroupVersionKind().Version, - Kind: t.GroupVersionKind().Kind, + Group: v1alpha1.SchemeGroupVersion.Group, + Version: v1alpha1.SchemeGroupVersion.Version, + Kind: "Trigger", }), }, }, @@ -363,9 +363,9 @@ func newVirtualService(t *v1alpha1.Trigger, svc *corev1.Service) *istiov1alpha3. Labels: virtualServiceLabels(t), OwnerReferences: []metav1.OwnerReference{ *metav1.NewControllerRef(t, schema.GroupVersionKind{ - Group: t.GroupVersionKind().Group, - Version: t.GroupVersionKind().Version, - Kind: t.GroupVersionKind().Kind, + Group: v1alpha1.SchemeGroupVersion.Group, + Version: v1alpha1.SchemeGroupVersion.Version, + Kind: "Trigger", }), }, }, @@ -459,9 +459,9 @@ func makeSubscription(t *v1alpha1.Trigger, c *v1alpha1.Channel, svc *corev1.Serv GenerateName: fmt.Sprintf("%s-%s-", t.Spec.Broker, t.Name), OwnerReferences: []metav1.OwnerReference{ *metav1.NewControllerRef(t, schema.GroupVersionKind{ - Group: t.GroupVersionKind().Group, - Version: t.GroupVersionKind().Version, - Kind: t.GroupVersionKind().Kind, + Group: v1alpha1.SchemeGroupVersion.Group, + Version: v1alpha1.SchemeGroupVersion.Version, + Kind: "Trigger", }), }, Labels: subscriptionLabels(t), From 054c10d15dc1bd71eddd62c4ea337f8ae9e23f56 Mon Sep 17 00:00:00 2001 From: Adam Harwayne Date: Tue, 5 Feb 2019 08:29:24 -0800 Subject: [PATCH 012/221] Add the Istio injection annotation. --- pkg/controller/eventing/broker/reconcile.go | 2 +- pkg/controller/eventing/broker/resources/filter.go | 5 ++++- pkg/controller/eventing/broker/resources/ingress.go | 5 ++++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/pkg/controller/eventing/broker/reconcile.go b/pkg/controller/eventing/broker/reconcile.go index 4a380fc0bfe..095b0a01846 100644 --- a/pkg/controller/eventing/broker/reconcile.go +++ b/pkg/controller/eventing/broker/reconcile.go @@ -277,7 +277,7 @@ func newChannel(b *v1alpha1.Broker) *v1alpha1.Channel { func ChannelLabels(b *v1alpha1.Broker) map[string]string { return map[string]string{ "eventing.knative.dev/broker": b.Name, - "eventing.knative.dev/broker/everything": "true", + "eventing.knative.dev/brokerEverything": "true", } } diff --git a/pkg/controller/eventing/broker/resources/filter.go b/pkg/controller/eventing/broker/resources/filter.go index 8e3aad3b12b..a87af55f5a6 100644 --- a/pkg/controller/eventing/broker/resources/filter.go +++ b/pkg/controller/eventing/broker/resources/filter.go @@ -52,6 +52,9 @@ func MakeFilterDeployment(args *FilterArgs) (*appsv1.Deployment, error) { Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ Labels: filterLabels(args.Broker), + Annotations: map[string]string{ + "sidecar.istio.io/inject": "true", + }, }, Spec: corev1.PodSpec{ ServiceAccountName: args.ServiceAccountName, @@ -102,6 +105,6 @@ func MakeFilterService(b *eventingv1alpha1.Broker) *corev1.Service { func filterLabels(b *eventingv1alpha1.Broker) map[string]string { return map[string]string{ "eventing.knative.dev/broker": b.Name, - "eventing.knative.dev/broker/role": "filter", + "eventing.knative.dev/brokerRole": "filter", } } diff --git a/pkg/controller/eventing/broker/resources/ingress.go b/pkg/controller/eventing/broker/resources/ingress.go index 33777f28c21..3a068f8b8c3 100644 --- a/pkg/controller/eventing/broker/resources/ingress.go +++ b/pkg/controller/eventing/broker/resources/ingress.go @@ -53,6 +53,9 @@ func MakeIngress(args *IngressArgs) (*appsv1.Deployment, error) { Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ Labels: ingressLabels(args.Broker), + Annotations: map[string]string{ + "sidecar.istio.io/inject": "true", + }, }, Spec: corev1.PodSpec{ ServiceAccountName: args.ServiceAccountName, @@ -107,6 +110,6 @@ func MakeIngressService(b *eventingv1alpha1.Broker) *corev1.Service { func ingressLabels(b *eventingv1alpha1.Broker) map[string]string { return map[string]string{ "eventing.knative.dev/broker": b.Name, - "eventing.knative.dev/broker/role": "ingress", + "eventing.knative.dev/brokerRole": "ingress", } } From 942b97987bee3264a599dfcc273ff32b49ae5364 Mon Sep 17 00:00:00 2001 From: Adam Harwayne Date: Tue, 5 Feb 2019 09:11:54 -0800 Subject: [PATCH 013/221] Resolve subscriber in the Trigger controller. --- .../eventing/subscription/reconcile.go | 26 +++++++++---------- pkg/controller/eventing/trigger/reconcile.go | 9 +++++++ t.yaml | 13 ++++++++++ 3 files changed, 35 insertions(+), 13 deletions(-) create mode 100644 t.yaml diff --git a/pkg/controller/eventing/subscription/reconcile.go b/pkg/controller/eventing/subscription/reconcile.go index def95e2a1a0..251982b9d3f 100644 --- a/pkg/controller/eventing/subscription/reconcile.go +++ b/pkg/controller/eventing/subscription/reconcile.go @@ -118,14 +118,14 @@ func (r *reconciler) reconcile(subscription *v1alpha1.Subscription) error { } // Verify that `channel` exists. - _, err = r.fetchObjectReference(subscription.Namespace, &subscription.Spec.Channel) + _, err = fetchObjectReference(r.dynamicClient, subscription.Namespace, &subscription.Spec.Channel) if err != nil { glog.Warningf("Failed to validate `channel` exists: %+v, %v", subscription.Spec.Channel, err) r.recorder.Eventf(subscription, corev1.EventTypeWarning, channelReferenceFetchFailed, "Failed to validate spec.channel exists: %v", err) return err } - if subscriberURI, err := r.resolveSubscriberSpec(subscription.Namespace, subscription.Spec.Subscriber); err != nil { + if subscriberURI, err := ResolveSubscriberSpec(context.TODO(), r.client, r.dynamicClient, subscription.Namespace, subscription.Spec.Subscriber); err != nil { glog.Warningf("Failed to resolve Subscriber %+v : %s", *subscription.Spec.Subscriber, err) r.recorder.Eventf(subscription, corev1.EventTypeWarning, subscriberResolveFailed, "Failed to resolve spec.subscriber: %v", err) return err @@ -207,12 +207,12 @@ func (r *reconciler) updateStatus(subscription *v1alpha1.Subscription) (*v1alpha return latestSubscription, nil } -// resolveSubscriberSpec resolves the Spec.Call object. If it's an +// ResolveSubscriberSpec resolves the Spec.Call object. If it's an // ObjectReference will resolve the object and treat it as a Callable. If // it's DNSName then it's used as is. // TODO: Once Service Routes, etc. support Callable, use that. // -func (r *reconciler) resolveSubscriberSpec(namespace string, s *v1alpha1.SubscriberSpec) (string, error) { +func ResolveSubscriberSpec(ctx context.Context, client client.Client, dynamicClient dynamic.Interface, namespace string, s *v1alpha1.SubscriberSpec) (string, error) { if isNilOrEmptySubscriber(s) { return "", nil } @@ -228,7 +228,7 @@ func (r *reconciler) resolveSubscriberSpec(namespace string, s *v1alpha1.Subscri Namespace: namespace, Name: s.Ref.Name, } - err := r.client.Get(context.TODO(), svcKey, svc) + err := client.Get(ctx, svcKey, svc) if err != nil { glog.Warningf("Failed to fetch SubscriberSpec target as a K8s Service %+v: %s", s.Ref, err) return "", err @@ -236,7 +236,7 @@ func (r *reconciler) resolveSubscriberSpec(namespace string, s *v1alpha1.Subscri return domainToURL(controller.ServiceHostName(svc.Name, svc.Namespace)), nil } - obj, err := r.fetchObjectReference(namespace, s.Ref) + obj, err := fetchObjectReference(dynamicClient, namespace, s.Ref) if err != nil { glog.Warningf("Failed to fetch SubscriberSpec target %+v: %s", s.Ref, err) return "", err @@ -263,7 +263,7 @@ func (r *reconciler) resolveResult(namespace string, replyStrategy *v1alpha1.Rep if isNilOrEmptyReply(replyStrategy) { return "", nil } - obj, err := r.fetchObjectReference(namespace, replyStrategy.Channel) + obj, err := fetchObjectReference(r.dynamicClient, namespace, replyStrategy.Channel) if err != nil { glog.Warningf("Failed to fetch ReplyStrategy channel %+v: %s", replyStrategy, err) return "", err @@ -281,8 +281,8 @@ func (r *reconciler) resolveResult(namespace string, replyStrategy *v1alpha1.Rep } // fetchObjectReference fetches an object based on ObjectReference. -func (r *reconciler) fetchObjectReference(namespace string, ref *corev1.ObjectReference) (duck.Marshalable, error) { - resourceClient, err := r.CreateResourceInterface(namespace, ref) +func fetchObjectReference(dynamicClient dynamic.Interface, namespace string, ref *corev1.ObjectReference) (duck.Marshalable, error) { + resourceClient, err := createResourceInterface(dynamicClient, namespace, ref) if err != nil { glog.Warningf("failed to create dynamic client resource: %v", err) return nil, err @@ -387,7 +387,7 @@ func (r *reconciler) createSubscribable(subs []v1alpha1.Subscription) *eventingd func (r *reconciler) patchPhysicalFrom(namespace string, physicalFrom corev1.ObjectReference, subs *eventingduck.Subscribable) error { // First get the original object and convert it to only the bits we care about - s, err := r.fetchObjectReference(namespace, &physicalFrom) + s, err := fetchObjectReference(r.dynamicClient, namespace, &physicalFrom) if err != nil { return err } @@ -411,7 +411,7 @@ func (r *reconciler) patchPhysicalFrom(namespace string, physicalFrom corev1.Obj return err } - resourceClient, err := r.CreateResourceInterface(namespace, &physicalFrom) + resourceClient, err := createResourceInterface(r.dynamicClient, namespace, &physicalFrom) if err != nil { glog.Warningf("failed to create dynamic client resource: %v", err) return err @@ -426,8 +426,8 @@ func (r *reconciler) patchPhysicalFrom(namespace string, physicalFrom corev1.Obj return nil } -func (r *reconciler) CreateResourceInterface(namespace string, ref *corev1.ObjectReference) (dynamic.ResourceInterface, error) { - rc := r.dynamicClient.Resource(duckapis.KindToResource(ref.GroupVersionKind())) +func createResourceInterface(dynamicClient dynamic.Interface, namespace string, ref *corev1.ObjectReference) (dynamic.ResourceInterface, error) { + rc := dynamicClient.Resource(duckapis.KindToResource(ref.GroupVersionKind())) if rc == nil { return nil, fmt.Errorf("failed to create dynamic client resource") diff --git a/pkg/controller/eventing/trigger/reconcile.go b/pkg/controller/eventing/trigger/reconcile.go index b1805336922..9d22f7620f6 100644 --- a/pkg/controller/eventing/trigger/reconcile.go +++ b/pkg/controller/eventing/trigger/reconcile.go @@ -22,6 +22,7 @@ import ( "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" "github.com/knative/eventing/pkg/controller" "github.com/knative/eventing/pkg/controller/eventing/broker" + "github.com/knative/eventing/pkg/controller/eventing/subscription" "github.com/knative/eventing/pkg/provisioners/gcppubsub/util/logging" istiov1alpha3 "github.com/knative/pkg/apis/istio/v1alpha3" "go.uber.org/zap" @@ -88,6 +89,7 @@ func (r *reconciler) reconcile(ctx context.Context, t *v1alpha1.Trigger) error { t.Status.InitializeConditions() // 1. Verify the Broker exists. + // 2. Find the Subscriber's URI. // 2. Creates a K8s Service uniquely named for this Trigger. // 3. Creates a VirtualService that routes the K8s Service to the Broker's filter service on an identifiable host name. // 4. Creates a Subscription from the Broker's single Channel to this Trigger's K8s Service, with reply set to the Broker. @@ -111,6 +113,13 @@ func (r *reconciler) reconcile(ctx context.Context, t *v1alpha1.Trigger) error { return err } + subscriberURI, err := subscription.ResolveSubscriberSpec(ctx, r.client, r.dynamicClient, t.Namespace, t.Spec.Subscriber) + if err != nil { + logging.FromContext(ctx).Error("Unable to get the Subscriber's URI", zap.Error(err)) + return err + } + t.Status.SubscriberURI = subscriberURI + svc, err := r.reconcileK8sService(ctx, t) if err != nil { logging.FromContext(ctx).Error("Unable to reconcile the K8s Service", zap.Error(err)) diff --git a/t.yaml b/t.yaml new file mode 100644 index 00000000000..aa125c7f99e --- /dev/null +++ b/t.yaml @@ -0,0 +1,13 @@ +apiVersion: eventing.knative.dev/v1alpha1 +kind: Trigger +metadata: + name: t +spec: + type: Any + source: Any + subscriber: + ref: + apiVersion: serving.knative.dev/v1alpha1 + kind: Service + name: message-dumper + From afd71af66d38cc4e665035bcd49264b511023753 Mon Sep 17 00:00:00 2001 From: Adam Harwayne Date: Tue, 5 Feb 2019 09:18:46 -0800 Subject: [PATCH 014/221] Standardize on 'Any'. --- pkg/apis/eventing/v1alpha1/trigger_defaults.go | 2 +- t.yaml | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/pkg/apis/eventing/v1alpha1/trigger_defaults.go b/pkg/apis/eventing/v1alpha1/trigger_defaults.go index ac2dfdf843f..fd785c8bf38 100644 --- a/pkg/apis/eventing/v1alpha1/trigger_defaults.go +++ b/pkg/apis/eventing/v1alpha1/trigger_defaults.go @@ -25,6 +25,6 @@ func (ts *TriggerSpec) SetDefaults() { ts.Broker = "default" } if ts.Type == "" { - ts.Type = "ANY" + ts.Type = "Any" } } diff --git a/t.yaml b/t.yaml index aa125c7f99e..a53dcc1db33 100644 --- a/t.yaml +++ b/t.yaml @@ -4,7 +4,6 @@ metadata: name: t spec: type: Any - source: Any subscriber: ref: apiVersion: serving.knative.dev/v1alpha1 From 7a1f69b3cad704a95dad553de6ad719db5325806 Mon Sep 17 00:00:00 2001 From: Adam Harwayne Date: Tue, 5 Feb 2019 11:23:36 -0800 Subject: [PATCH 015/221] Make Broker and Trigger generational --- cmd/webhook/main.go | 3 ++- pkg/apis/eventing/v1alpha1/broker_types.go | 9 +++++++++ pkg/apis/eventing/v1alpha1/trigger_types.go | 9 +++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/cmd/webhook/main.go b/cmd/webhook/main.go index 400a452cd9a..b0e25711735 100644 --- a/cmd/webhook/main.go +++ b/cmd/webhook/main.go @@ -107,5 +107,6 @@ func main() { if err != nil { logger.Fatal("Failed to create the admission controller", zap.Error(err)) } - controller.Run(stopCh) + err = controller.Run(stopCh) + logger.Errorw("Webhook stopping", zap.Error(err)) } diff --git a/pkg/apis/eventing/v1alpha1/broker_types.go b/pkg/apis/eventing/v1alpha1/broker_types.go index d3c2c5b4e2a..fa0ba9b7c93 100644 --- a/pkg/apis/eventing/v1alpha1/broker_types.go +++ b/pkg/apis/eventing/v1alpha1/broker_types.go @@ -49,6 +49,15 @@ var _ runtime.Object = (*Broker)(nil) var _ webhook.GenericCRD = (*Broker)(nil) type BrokerSpec struct { + // TODO By enabling the status subresource metadata.generation should increment + // thus making this property obsolete. + // + // We should be able to drop this property with a CRD conversion webhook + // in the future + // + // +optional + DeprecatedGeneration int64 `json:"generation,omitempty"` + ChannelTemplate *ChannelSpec `json:"channelTemplate,omitempty"` } diff --git a/pkg/apis/eventing/v1alpha1/trigger_types.go b/pkg/apis/eventing/v1alpha1/trigger_types.go index 47d1ab5f5fe..e2c3529b418 100644 --- a/pkg/apis/eventing/v1alpha1/trigger_types.go +++ b/pkg/apis/eventing/v1alpha1/trigger_types.go @@ -49,6 +49,15 @@ var _ runtime.Object = (*Trigger)(nil) var _ webhook.GenericCRD = (*Trigger)(nil) type TriggerSpec struct { + // TODO By enabling the status subresource metadata.generation should increment + // thus making this property obsolete. + // + // We should be able to drop this property with a CRD conversion webhook + // in the future + // + // +optional + DeprecatedGeneration int64 `json:"generation,omitempty"` + Broker string `json:"broker,omitempty"` Subscriber *SubscriberSpec `json:"subscriber,omitempty"` From 2be56bd789b6896d12c24cdcefaf9f2f3666254e Mon Sep 17 00:00:00 2001 From: Adam Harwayne Date: Tue, 5 Feb 2019 12:16:35 -0800 Subject: [PATCH 016/221] Happy control path. --- pkg/apis/eventing/v1alpha1/trigger_types.go | 4 ++-- pkg/controller/eventing/broker/reconcile.go | 18 +++++++++-------- pkg/controller/eventing/trigger/reconcile.go | 21 ++++++++++---------- 3 files changed, 23 insertions(+), 20 deletions(-) diff --git a/pkg/apis/eventing/v1alpha1/trigger_types.go b/pkg/apis/eventing/v1alpha1/trigger_types.go index e2c3529b418..3e2c1d0c654 100644 --- a/pkg/apis/eventing/v1alpha1/trigger_types.go +++ b/pkg/apis/eventing/v1alpha1/trigger_types.go @@ -121,11 +121,11 @@ func (ts *TriggerStatus) MarkBrokerDoesNotExists() { triggerCondSet.Manage(ts).MarkFalse(TriggerConditionBrokerExists, "doesNotExist", "Broker does not exist") } -func (ts *TriggerSpec) MarkKubernetesServiceExists() { +func (ts *TriggerStatus) MarkKubernetesServiceExists() { triggerCondSet.Manage(ts).MarkTrue(TriggerConditionKubernetesService) } -func (ts *TriggerSpec) MarkVirtualServiceExists() { +func (ts *TriggerStatus) MarkVirtualServiceExists() { triggerCondSet.Manage(ts).MarkTrue(TriggerConditionVirtualService) } diff --git a/pkg/controller/eventing/broker/reconcile.go b/pkg/controller/eventing/broker/reconcile.go index 095b0a01846..2ce00bb10f9 100644 --- a/pkg/controller/eventing/broker/reconcile.go +++ b/pkg/controller/eventing/broker/reconcile.go @@ -211,16 +211,17 @@ func (r *reconciler) reconcileChannel(ctx context.Context, b *v1alpha1.Broker) ( return nil, err } + // TODO Determine if we want to update spec (maybe just args?). // Update Channel if it has changed. Note that we need to both ignore the real Channel's // subscribable section and if we need to update the real Channel, retain it. - expected.Spec.Subscribable = c.Spec.Subscribable - if !equality.Semantic.DeepDerivative(expected.Spec, c.Spec) { - c.Spec = expected.Spec - err = r.client.Update(ctx, c) - if err != nil { - return nil, err - } - } + //expected.Spec.Subscribable = c.Spec.Subscribable + //if !equality.Semantic.DeepDerivative(expected.Spec, c.Spec) { + // c.Spec = expected.Spec + // err = r.client.Update(ctx, c) + // if err != nil { + // return nil, err + // } + //} return c, nil } @@ -262,6 +263,7 @@ func newChannel(b *v1alpha1.Broker) *v1alpha1.Channel { ObjectMeta: metav1.ObjectMeta{ Namespace: b.Namespace, GenerateName: fmt.Sprintf("%s-broker-", b.Name), + Labels: ChannelLabels(b), OwnerReferences: []metav1.OwnerReference{ *metav1.NewControllerRef(b, schema.GroupVersionKind{ Group: v1alpha1.SchemeGroupVersion.Group, diff --git a/pkg/controller/eventing/trigger/reconcile.go b/pkg/controller/eventing/trigger/reconcile.go index 9d22f7620f6..4e461d340b1 100644 --- a/pkg/controller/eventing/trigger/reconcile.go +++ b/pkg/controller/eventing/trigger/reconcile.go @@ -125,12 +125,14 @@ func (r *reconciler) reconcile(ctx context.Context, t *v1alpha1.Trigger) error { logging.FromContext(ctx).Error("Unable to reconcile the K8s Service", zap.Error(err)) return err } + t.Status.MarkKubernetesServiceExists() _, err = r.reconcileVirtualService(ctx, t, svc) if err != nil { logging.FromContext(ctx).Error("Unable to reconcile the VirtualService", zap.Error(err)) return err } + t.Status.MarkVirtualServiceExists() _, err = r.subscribeToBrokerChannel(ctx, t, c, svc) if err != nil { @@ -422,7 +424,8 @@ func (r *reconciler) subscribeToBrokerChannel(ctx context.Context, t *v1alpha1.T return nil, err } - // Update Subscription if it has changed. + // Update Subscription if it has changed. Ignore the generation. + expected.Spec.DeprecatedGeneration = sub.Spec.DeprecatedGeneration if !equality.Semantic.DeepDerivative(expected.Spec, sub.Spec) { sub.Spec = expected.Spec err = r.client.Update(ctx, sub) @@ -477,24 +480,22 @@ func makeSubscription(t *v1alpha1.Trigger, c *v1alpha1.Channel, svc *corev1.Serv }, Spec: v1alpha1.SubscriptionSpec{ Channel: corev1.ObjectReference{ - APIVersion: c.APIVersion, - Kind: c.Kind, - Namespace: c.Namespace, + APIVersion: v1alpha1.SchemeGroupVersion.String(), + Kind: "Channel", Name: c.Name, }, Subscriber: &v1alpha1.SubscriberSpec{ Ref: &corev1.ObjectReference{ - APIVersion: svc.APIVersion, - Kind: svc.Kind, - Namespace: svc.Namespace, + APIVersion: "v1", + Kind: "Service", Name: svc.Name, }, }, + // TODO This pushes directly into the Channel, it should probably point at the Broker ingress instead. Reply: &v1alpha1.ReplyStrategy{ Channel: &corev1.ObjectReference{ - APIVersion: c.APIVersion, - Kind: c.Kind, - Namespace: c.Namespace, + APIVersion: v1alpha1.SchemeGroupVersion.String(), + Kind: "Channel", Name: c.Name, }, }, From 10acfa388a43dba6b2b438e1fae065b6dda2b0c9 Mon Sep 17 00:00:00 2001 From: Adam Harwayne Date: Tue, 5 Feb 2019 13:05:16 -0800 Subject: [PATCH 017/221] TargetPort is 8080 --- cmd/broker/ingress/main.go | 9 +++++++-- pkg/controller/eventing/broker/reconcile.go | 4 +--- pkg/controller/eventing/broker/resources/filter.go | 2 +- pkg/controller/eventing/broker/resources/ingress.go | 2 ++ 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/cmd/broker/ingress/main.go b/cmd/broker/ingress/main.go index 865d07db82e..37b96da1412 100644 --- a/cmd/broker/ingress/main.go +++ b/cmd/broker/ingress/main.go @@ -19,6 +19,7 @@ package main import ( "context" "flag" + "fmt" "golang.org/x/sync/errgroup" "log" "net/http" @@ -113,7 +114,7 @@ func NewHandler(logger *zap.Logger, destination string) *Handler { handler := &Handler{ logger: logger, dispatcher: provisioners.NewMessageDispatcher(logger.Sugar()), - destination: destination, + destination: fmt.Sprintf("http://%s", destination), } // The receiver function needs to point back at the handler itself, so set it up after // initialization. @@ -136,7 +137,11 @@ func (f *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { // dispatch takes the request, fans it out to each subscription in f.config. If all the fanned out // requests return successfully, then return nil. Else, return an error. func (f *Handler) dispatch(msg *provisioners.Message) error { - return f.dispatcher.DispatchMessage(msg, f.destination, "", provisioners.DispatchDefaults{}) + err := f.dispatcher.DispatchMessage(msg, f.destination, "", provisioners.DispatchDefaults{}) + if err != nil { + f.logger.Error("Error dispatching message", zap.String("destination", f.destination)) + } + return err } diff --git a/pkg/controller/eventing/broker/reconcile.go b/pkg/controller/eventing/broker/reconcile.go index 2ce00bb10f9..ea0fef23c83 100644 --- a/pkg/controller/eventing/broker/reconcile.go +++ b/pkg/controller/eventing/broker/reconcile.go @@ -196,12 +196,10 @@ func (r *reconciler) reconcileFilterService(ctx context.Context, b *v1alpha1.Bro } func (r *reconciler) reconcileChannel(ctx context.Context, b *v1alpha1.Broker) (*v1alpha1.Channel, error) { - expected := newChannel(b) - c, err := r.getChannel(ctx, b) // If the resource doesn't exist, we'll create it if k8serrors.IsNotFound(err) { - c = expected + c = newChannel(b) err = r.client.Create(ctx, c) if err != nil { return nil, err diff --git a/pkg/controller/eventing/broker/resources/filter.go b/pkg/controller/eventing/broker/resources/filter.go index a87af55f5a6..c05cc960e96 100644 --- a/pkg/controller/eventing/broker/resources/filter.go +++ b/pkg/controller/eventing/broker/resources/filter.go @@ -61,7 +61,7 @@ func MakeFilterDeployment(args *FilterArgs) (*appsv1.Deployment, error) { Containers: []corev1.Container{ { Image: args.Image, - Name: "ingress", + Name: "filter", Env: []corev1.EnvVar{ { Name: "BROKER", diff --git a/pkg/controller/eventing/broker/resources/ingress.go b/pkg/controller/eventing/broker/resources/ingress.go index 3a068f8b8c3..4f6933116f9 100644 --- a/pkg/controller/eventing/broker/resources/ingress.go +++ b/pkg/controller/eventing/broker/resources/ingress.go @@ -19,6 +19,7 @@ package resources import ( "fmt" appsv1 "k8s.io/api/apps/v1" + "k8s.io/apimachinery/pkg/util/intstr" eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" corev1 "k8s.io/api/core/v1" @@ -101,6 +102,7 @@ func MakeIngressService(b *eventingv1alpha1.Broker) *corev1.Service { { Name: "http", Port: 80, + TargetPort: intstr.FromInt(8080), }, }, }, From 2108d837ee01123b22073538a5ca002256bad960 Mon Sep 17 00:00:00 2001 From: Adam Harwayne Date: Tue, 5 Feb 2019 13:30:24 -0800 Subject: [PATCH 018/221] Watch channels. --- pkg/controller/eventing/broker/provider.go | 7 +++++++ pkg/controller/eventing/broker/reconcile.go | 4 ++++ pkg/controller/eventing/broker/resources/filter.go | 2 ++ 3 files changed, 13 insertions(+) diff --git a/pkg/controller/eventing/broker/provider.go b/pkg/controller/eventing/broker/provider.go index b3655a72ba1..5d94c8cbcfb 100644 --- a/pkg/controller/eventing/broker/provider.go +++ b/pkg/controller/eventing/broker/provider.go @@ -77,6 +77,13 @@ func ProvideController(logger *zap.Logger, ingressImage, ingressServiceAccount, return nil, err } + err = c.Watch(&source.Kind{ + Type: &v1alpha1.Channel{}, + }, &handler.EnqueueRequestForOwner{OwnerType: &v1alpha1.Broker{}, IsController: true}) + if err != nil { + return nil, err + } + return c, nil } } diff --git a/pkg/controller/eventing/broker/reconcile.go b/pkg/controller/eventing/broker/reconcile.go index ea0fef23c83..5837fcbfddb 100644 --- a/pkg/controller/eventing/broker/reconcile.go +++ b/pkg/controller/eventing/broker/reconcile.go @@ -106,6 +106,10 @@ func (r *reconciler) reconcile(ctx context.Context, b *v1alpha1.Broker) error { logging.FromContext(ctx).Error("Problem reconciling the channel", zap.Error(err)) b.Status.MarkChannelFailed(err) return err + } else if c.Status.Address.Hostname == "" { + logging.FromContext(ctx).Info("Channel is not yet ready", zap.Any("c", c)) + // TODO Just re-enqueue, don't return an error + return nil } b.Status.MarkChannelReady() diff --git a/pkg/controller/eventing/broker/resources/filter.go b/pkg/controller/eventing/broker/resources/filter.go index c05cc960e96..dcb330c5570 100644 --- a/pkg/controller/eventing/broker/resources/filter.go +++ b/pkg/controller/eventing/broker/resources/filter.go @@ -19,6 +19,7 @@ package resources import ( "fmt" appsv1 "k8s.io/api/apps/v1" + "k8s.io/apimachinery/pkg/util/intstr" eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" corev1 "k8s.io/api/core/v1" @@ -96,6 +97,7 @@ func MakeFilterService(b *eventingv1alpha1.Broker) *corev1.Service { { Name: "http", Port: 80, + TargetPort: intstr.FromInt(8080), }, }, }, From 6aa70860a553a05903536be0664347addb7764a8 Mon Sep 17 00:00:00 2001 From: Adam Harwayne Date: Tue, 5 Feb 2019 13:45:53 -0800 Subject: [PATCH 019/221] Custom service account for filter (needs trigger watch). --- config/500-controller.yaml | 2 +- sa.yaml | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 sa.yaml diff --git a/config/500-controller.yaml b/config/500-controller.yaml index 1c6e9336154..607707fa3f9 100644 --- a/config/500-controller.yaml +++ b/config/500-controller.yaml @@ -43,7 +43,7 @@ spec: - name: FILTER_IMAGE value: github.com/knative/eventing/cmd/broker/filter - name: FILTER_SERVICE_ACCOUNT - value: default + value: broker-filter volumeMounts: - name: config-logging mountPath: /etc/config-logging diff --git a/sa.yaml b/sa.yaml new file mode 100644 index 00000000000..124edb3f340 --- /dev/null +++ b/sa.yaml @@ -0,0 +1,20 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: broker-filter + namespace: default + +--- + +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: broker-filter +subjects: + - kind: ServiceAccount + name: broker-filter + namespace: default +roleRef: + kind: ClusterRole + name: cluster-admin + apiGroup: rbac.authorization.k8s.io From 3cd236f0606014ec17deca0db843b230bd0d77aa Mon Sep 17 00:00:00 2001 From: Adam Harwayne Date: Tue, 5 Feb 2019 15:39:39 -0800 Subject: [PATCH 020/221] Increase logging in the Filter to debug level. --- cmd/broker/filter/main.go | 2 ++ pkg/broker/filter.go | 21 +++++++++++---------- t2.yaml | 14 ++++++++++++++ 3 files changed, 27 insertions(+), 10 deletions(-) create mode 100644 t2.yaml diff --git a/cmd/broker/filter/main.go b/cmd/broker/filter/main.go index a8f2f8536a8..f31dcee677f 100644 --- a/cmd/broker/filter/main.go +++ b/cmd/broker/filter/main.go @@ -23,12 +23,14 @@ import ( "github.com/knative/eventing/pkg/provisioners" "github.com/knative/pkg/signals" "go.uber.org/zap" + "go.uber.org/zap/zapcore" "sigs.k8s.io/controller-runtime/pkg/client/config" "sigs.k8s.io/controller-runtime/pkg/manager" ) func main() { logConfig := provisioners.NewLoggingConfig() + logConfig.LoggingLevel["provisioner"] = zapcore.DebugLevel logger := provisioners.NewProvisionerLoggerFromConfig(logConfig).Desugar() defer logger.Sync() diff --git a/pkg/broker/filter.go b/pkg/broker/filter.go index cb542a2e060..a0e467dd942 100644 --- a/pkg/broker/filter.go +++ b/pkg/broker/filter.go @@ -22,7 +22,6 @@ import ( eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" "github.com/knative/eventing/pkg/provisioners" - "github.com/knative/eventing/pkg/provisioners/gcppubsub/util/logging" "go.uber.org/zap" "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" @@ -63,27 +62,27 @@ func (r *Receiver) sendEventToTopic(channel provisioners.ChannelReference, messa t, err := r.getTrigger(ctx, channel) if err != nil { - logging.FromContext(ctx).Info("Unable to get the Trigger", zap.Error(err), zap.Any("channelRef", channel)) + r.logger.Info("Unable to get the Trigger", zap.Error(err), zap.Any("channelRef", channel)) return err } subscriberURI := t.Status.SubscriberURI if subscriberURI == "" { - logging.FromContext(ctx).Error("Unable to read subscriberURI") + r.logger.Error("Unable to read subscriberURI") return errors.New("unable to read subscriberURI") } - if !shouldSendMessage(t.Spec, message) { - logging.FromContext(ctx).Debug("Message did not pass filter") + if !r.shouldSendMessage(&t.Spec, message) { + r.logger.Debug("Message did not pass filter") return nil } err = r.dispatcher.DispatchMessage(message, subscriberURI, "", provisioners.DispatchDefaults{}) if err != nil { - logging.FromContext(ctx).Info("Failed to dispatch message", zap.Error(err)) + r.logger.Info("Failed to dispatch message", zap.Error(err)) return err } - logging.FromContext(ctx).Debug("Successfully sent message") + r.logger.Debug("Successfully sent message") return nil } @@ -98,12 +97,14 @@ func (r *Receiver) getTrigger(ctx context.Context, ref provisioners.ChannelRefer return t, err } -func shouldSendMessage(t eventingv1alpha1.TriggerSpec, m *provisioners.Message) bool { +func (r *Receiver) shouldSendMessage(t *eventingv1alpha1.TriggerSpec, m *provisioners.Message) bool { // TODO More filtering! - if t.Type != Any && t.Type != m.Headers["type"] { + if t.Type != Any && t.Type != m.Headers["Ce-Eventtype"] { + r.logger.Debug("Wrong type", zap.String("trigger.spec.type", t.Type), zap.String("message.type", m.Headers["Ce-Eventtype"]), zap.Any("m", m)) return false } - if t.Source != "" && t.Source != m.Headers["source"] { + if t.Source != "" && t.Source != m.Headers["Ce-Source"] { + r.logger.Debug("Wrong source", zap.String("trigger.spec.source", t.Source), zap.String("message.source", m.Headers["Ce-Source"])) return false } return true diff --git a/t2.yaml b/t2.yaml new file mode 100644 index 00000000000..0e217789a03 --- /dev/null +++ b/t2.yaml @@ -0,0 +1,14 @@ +apiVersion: eventing.knative.dev/v1alpha1 +kind: Trigger +metadata: + name: t +spec: + # Our Cloud Event parsing library seems to have a bug and forces to put type and source in double + # quotes (as it thinks the actual value is `"foo"`, not `foo`). + type: '"com.example.someevent"' + subscriber: + ref: + apiVersion: serving.knative.dev/v1alpha1 + kind: Service + name: message-dumper + From be350a00d705448bf4cbcf7d9253166589db4e72 Mon Sep 17 00:00:00 2001 From: Adam Harwayne Date: Tue, 5 Feb 2019 16:06:24 -0800 Subject: [PATCH 021/221] Use the default channel provisioner. --- b2.yaml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 b2.yaml diff --git a/b2.yaml b/b2.yaml new file mode 100644 index 00000000000..1c0f7b43a82 --- /dev/null +++ b/b2.yaml @@ -0,0 +1,5 @@ +apiVersion: eventing.knative.dev/v1alpha1 +kind: Broker +metadata: + name: default +spec: {} From 0068232867f6e5f4ccc7326369ec5d954a43d4d8 Mon Sep 17 00:00:00 2001 From: nachocano Date: Tue, 5 Feb 2019 16:35:17 -0800 Subject: [PATCH 022/221] Adding filtering using k8s label selectors --- .../eventing/v1alpha1/trigger_defaults.go | 10 +++++-- pkg/apis/eventing/v1alpha1/trigger_types.go | 7 +++-- .../eventing/v1alpha1/trigger_validation.go | 4 +-- .../v1alpha1/zz_generated.deepcopy.go | 10 +++++++ pkg/broker/filter.go | 26 +++++++++++-------- 5 files changed, 38 insertions(+), 19 deletions(-) diff --git a/pkg/apis/eventing/v1alpha1/trigger_defaults.go b/pkg/apis/eventing/v1alpha1/trigger_defaults.go index fd785c8bf38..334be735fa6 100644 --- a/pkg/apis/eventing/v1alpha1/trigger_defaults.go +++ b/pkg/apis/eventing/v1alpha1/trigger_defaults.go @@ -16,6 +16,8 @@ limitations under the License. package v1alpha1 +import v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + func (t *Trigger) SetDefaults() { t.Spec.SetDefaults() } @@ -24,7 +26,11 @@ func (ts *TriggerSpec) SetDefaults() { if ts.Broker == "" { ts.Broker = "default" } - if ts.Type == "" { - ts.Type = "Any" + // Make an empty LabelSelector so that we allow everything. + if ts.Filters == nil { + ts.Filters = &v1.LabelSelector{ + MatchLabels: make(map[string]string, 0), + MatchExpressions: make([]v1.LabelSelectorRequirement, 0), + } } } diff --git a/pkg/apis/eventing/v1alpha1/trigger_types.go b/pkg/apis/eventing/v1alpha1/trigger_types.go index 3e2c1d0c654..303f57cb8d2 100644 --- a/pkg/apis/eventing/v1alpha1/trigger_types.go +++ b/pkg/apis/eventing/v1alpha1/trigger_types.go @@ -58,11 +58,10 @@ type TriggerSpec struct { // +optional DeprecatedGeneration int64 `json:"generation,omitempty"` - Broker string `json:"broker,omitempty"` - Subscriber *SubscriberSpec `json:"subscriber,omitempty"` + Broker string `json:"broker,omitempty"` + Subscriber *SubscriberSpec `json:"subscriber,omitempty"` - Type string `json:"type,omitempty"` - Source string `json:"source,omitempty"` + Filters *metav1.LabelSelector `json:"filters,omitempty"` } var triggerCondSet = duckv1alpha1.NewLivingConditionSet(TriggerConditionBrokerExists, TriggerConditionKubernetesService, TriggerConditionVirtualService, TriggerConditionSubscribed) diff --git a/pkg/apis/eventing/v1alpha1/trigger_validation.go b/pkg/apis/eventing/v1alpha1/trigger_validation.go index 9d0178a464f..e93b2f60195 100644 --- a/pkg/apis/eventing/v1alpha1/trigger_validation.go +++ b/pkg/apis/eventing/v1alpha1/trigger_validation.go @@ -32,8 +32,8 @@ func (ts *TriggerSpec) Validate() *apis.FieldError { errs = errs.Also(fe) } - if ts.Type == "" { - fe := apis.ErrMissingField("type") + if ts.Filters == nil { + fe := apis.ErrMissingField("filters") errs = errs.Also(fe) } diff --git a/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go index fc8f77d0aee..79fb64c6e3a 100644 --- a/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go @@ -24,6 +24,7 @@ import ( apis_duck_v1alpha1 "github.com/knative/eventing/pkg/apis/duck/v1alpha1" duck_v1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" v1 "k8s.io/api/core/v1" + meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" ) @@ -642,6 +643,15 @@ func (in *TriggerSpec) DeepCopyInto(out *TriggerSpec) { (*in).DeepCopyInto(*out) } } + if in.Filters != nil { + in, out := &in.Filters, &out.Filters + if *in == nil { + *out = nil + } else { + *out = new(meta_v1.LabelSelector) + (*in).DeepCopyInto(*out) + } + } return } diff --git a/pkg/broker/filter.go b/pkg/broker/filter.go index cb542a2e060..449e65b5f20 100644 --- a/pkg/broker/filter.go +++ b/pkg/broker/filter.go @@ -20,6 +20,10 @@ import ( "context" "errors" + "k8s.io/apimachinery/pkg/labels" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" "github.com/knative/eventing/pkg/provisioners" "github.com/knative/eventing/pkg/provisioners/gcppubsub/util/logging" @@ -45,8 +49,8 @@ type Receiver struct { // Start()ing the returned MessageReceiver. func New(logger *zap.Logger, client client.Client) (*Receiver, manager.Runnable) { r := &Receiver{ - logger: logger, - client: client, + logger: logger, + client: client, dispatcher: provisioners.NewMessageDispatcher(logger.Sugar()), } return r, r.newMessageReceiver() @@ -73,8 +77,8 @@ func (r *Receiver) sendEventToTopic(channel provisioners.ChannelReference, messa return errors.New("unable to read subscriberURI") } - if !shouldSendMessage(t.Spec, message) { - logging.FromContext(ctx).Debug("Message did not pass filter") + if !shouldSendMessage(ctx, t.Spec, message) { + logging.FromContext(ctx).Info("Message did not pass filter") return nil } @@ -98,13 +102,13 @@ func (r *Receiver) getTrigger(ctx context.Context, ref provisioners.ChannelRefer return t, err } -func shouldSendMessage(t eventingv1alpha1.TriggerSpec, m *provisioners.Message) bool { - // TODO More filtering! - if t.Type != Any && t.Type != m.Headers["type"] { - return false - } - if t.Source != "" && t.Source != m.Headers["source"] { +func shouldSendMessage(ctx context.Context, t eventingv1alpha1.TriggerSpec, m *provisioners.Message) bool { + // TODO, this conversion to selector should be done only once, possibly upon creation of the trigger + selector, err := v1.LabelSelectorAsSelector(t.Filters) + if err != nil { + logging.FromContext(ctx).Error("Invalid label selector for filter", zap.Error(err)) return false } - return true + l := labels.Set(m.Headers) + return selector.Matches(l) } From b4e2358745ea6ec453ba6ce43d8febe7359529b1 Mon Sep 17 00:00:00 2001 From: Adam Harwayne Date: Tue, 5 Feb 2019 16:40:01 -0800 Subject: [PATCH 023/221] Watch namespaces and create a default Broker. --- cmd/controller/main.go | 2 + pkg/controller/eventing/namespace/provider.go | 85 +++++++++++ .../eventing/namespace/reconcile.go | 135 ++++++++++++++++++ 3 files changed, 222 insertions(+) create mode 100644 pkg/controller/eventing/namespace/provider.go create mode 100644 pkg/controller/eventing/namespace/reconcile.go diff --git a/cmd/controller/main.go b/cmd/controller/main.go index 52661d99c5e..5eee4da37d1 100644 --- a/cmd/controller/main.go +++ b/cmd/controller/main.go @@ -19,6 +19,7 @@ package main import ( "context" "flag" + "github.com/knative/eventing/pkg/controller/eventing/namespace" "log" "net/http" "os" @@ -126,6 +127,7 @@ func main() { subscription.ProvideController, broker.ProvideController(logger.Desugar(), getRequiredEnv("INGRESS_IMAGE"), getRequiredEnv("INGRESS_SERVICE_ACCOUNT"), getRequiredEnv("FILTER_IMAGE"), getRequiredEnv("FILTER_SERVICE_ACCOUNT")), trigger.ProvideController(logger.Desugar()), + namespace.ProvideController(logger.Desugar()), } for _, provider := range providers { if _, err := provider(mgr); err != nil { diff --git a/pkg/controller/eventing/namespace/provider.go b/pkg/controller/eventing/namespace/provider.go new file mode 100644 index 00000000000..01648c6918f --- /dev/null +++ b/pkg/controller/eventing/namespace/provider.go @@ -0,0 +1,85 @@ +/* +Copyright 2018 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT 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 namespace + +import ( + "go.uber.org/zap" + "k8s.io/api/core/v1" + "k8s.io/client-go/dynamic" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/record" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller" + "sigs.k8s.io/controller-runtime/pkg/handler" + "sigs.k8s.io/controller-runtime/pkg/manager" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + "sigs.k8s.io/controller-runtime/pkg/source" +) + +const ( + // controllerAgentName is the string used by this controller to identify + // itself when creating events. + controllerAgentName = "knative-eventing-namespace-controller" +) + +type reconciler struct { + client client.Client + restConfig *rest.Config + dynamicClient dynamic.Interface + recorder record.EventRecorder + + logger *zap.Logger +} + +// Verify the struct implements reconcile.Reconciler +var _ reconcile.Reconciler = &reconciler{} + +// ProvideController returns a function that returns a Broker controller. +func ProvideController(logger *zap.Logger) func(manager.Manager) (controller.Controller, error) { + return func(mgr manager.Manager) (controller.Controller, error) { + // Setup a new controller to Reconcile Brokers. + r := &reconciler{ + recorder: mgr.GetRecorder(controllerAgentName), + logger: logger, + } + c, err := controller.New(controllerAgentName, mgr, controller.Options{ + Reconciler: r, + }) + if err != nil { + return nil, err + } + + // Watch Subscription events and enqueue Subscription object key. + if err = c.Watch(&source.Kind{Type: &v1.Namespace{}}, &handler.EnqueueRequestForObject{}); err != nil { + return nil, err + } + + return c, nil + } +} + +func (r *reconciler) InjectClient(c client.Client) error { + r.client = c + return nil +} + +func (r *reconciler) InjectConfig(c *rest.Config) error { + r.restConfig = c + var err error + r.dynamicClient, err = dynamic.NewForConfig(c) + return err +} diff --git a/pkg/controller/eventing/namespace/reconcile.go b/pkg/controller/eventing/namespace/reconcile.go new file mode 100644 index 00000000000..3185b04ca27 --- /dev/null +++ b/pkg/controller/eventing/namespace/reconcile.go @@ -0,0 +1,135 @@ +/* +Copyright 2018 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT 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 namespace + +import ( + "context" + "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" + "github.com/knative/eventing/pkg/provisioners/gcppubsub/util/logging" + "go.uber.org/zap" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" + k8serrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/reconcile" +) + +const ( + defaultBroker = "default" + KnativeEventingAnnotation = "eventing.knative.dev/injection" + + // Name of the corev1.Events emitted from the reconciliation process + brokerCreated = "BrokerCreated" +) + +// Reconcile compares the actual state with the desired, and attempts to +// converge the two. It then updates the Status block of the Trigger resource +// with the current status of the resource. +func (r *reconciler) Reconcile(request reconcile.Request) (reconcile.Result, error) { + ctx := context.TODO() + ctx = logging.WithLogger(ctx, r.logger.With(zap.Any("request", request))) + + ns := &corev1.Namespace{} + err := r.client.Get(context.TODO(), request.NamespacedName, ns) + + if errors.IsNotFound(err) { + logging.FromContext(ctx).Info("Could not find Namespace") + return reconcile.Result{}, nil + } + + if err != nil { + logging.FromContext(ctx).Error("Could not Get Namespace", zap.Error(err)) + return reconcile.Result{}, err + } + + if ns.Annotations[KnativeEventingAnnotation] != "true" { + logging.FromContext(ctx).Debug("Not reconciling Namespace") + return reconcile.Result{}, nil + } + + // Reconcile this copy of the Trigger and then write back any status updates regardless of + // whether the reconcile error out. + reconcileErr := r.reconcile(ctx, ns) + if reconcileErr != nil { + logging.FromContext(ctx).Error("Error reconciling Namespace", zap.Error(reconcileErr)) + } else { + logging.FromContext(ctx).Debug("Namespace reconciled") + } + + // Requeue if the resource is not ready: + return reconcile.Result{}, err +} + +func (r *reconciler) reconcile(ctx context.Context, ns *corev1.Namespace) error { + if ns.DeletionTimestamp != nil { + return nil + } + + _, err := r.reconcileBroker(ctx, ns) + if err != nil { + logging.FromContext(ctx).Error("Unable to reconcile broker for the namespace", zap.Error(err)) + return err + } + + return nil +} + +func (r *reconciler) getBroker(ctx context.Context, ns *corev1.Namespace) (*v1alpha1.Broker, error) { + b := &v1alpha1.Broker{} + name := types.NamespacedName{ + Namespace: ns.Name, + Name: defaultBroker, + } + err := r.client.Get(ctx, name, b) + return b, err +} + +func (r *reconciler) reconcileBroker(ctx context.Context, ns *corev1.Namespace) (*v1alpha1.Broker, error) { + current, err := r.getBroker(ctx, ns) + + // If the resource doesn't exist, we'll create it + if k8serrors.IsNotFound(err) { + b := newBroker(ns) + err = r.client.Create(ctx, b) + if err != nil { + return nil, err + } + r.recorder.Event(ns, corev1.EventTypeNormal, brokerCreated, "Default eventing.knative.dev Broker created.") + return b, nil + } else if err != nil { + return nil, err + } + // Don't update anything that is already present. + return current, nil +} + +func newBroker(ns *corev1.Namespace) *v1alpha1.Broker { + return &v1alpha1.Broker{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: ns.Name, + Name: defaultBroker, + Labels: brokerLabels(), + }, + } +} + +func brokerLabels() map[string]string { + return map[string]string{ + "eventing.knative.dev/brokerForNamespace": "true", + } +} From 5ca1b9f3003d35bc87e07f2c96a7976731103590 Mon Sep 17 00:00:00 2001 From: nachocano Date: Tue, 5 Feb 2019 16:47:04 -0800 Subject: [PATCH 024/221] Updating trigger example with filters --- t2.yaml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/t2.yaml b/t2.yaml index 0e217789a03..b912ba497a4 100644 --- a/t2.yaml +++ b/t2.yaml @@ -3,12 +3,14 @@ kind: Trigger metadata: name: t spec: - # Our Cloud Event parsing library seems to have a bug and forces to put type and source in double - # quotes (as it thinks the actual value is `"foo"`, not `foo`). - type: '"com.example.someevent"' subscriber: ref: apiVersion: serving.knative.dev/v1alpha1 kind: Service name: message-dumper - + # Our Cloud Event parsing library seems to have a bug and forces to put type and source in double + # quotes (as it thinks the actual value is `"foo"`, not `foo`). + filters: + matchLabels: + Ce-Eventtype: com.example.someevent + Ce-Source: mycontext From bd53cda0d17edabbad6b72e907331dd65463c8cf Mon Sep 17 00:00:00 2001 From: Adam Harwayne Date: Tue, 5 Feb 2019 21:35:41 -0800 Subject: [PATCH 025/221] Broker changes cause the namespace watcher to reconcile. --- pkg/controller/eventing/broker/reconcile.go | 2 +- pkg/controller/eventing/namespace/provider.go | 20 +++++++++++++++++++ .../eventing/namespace/reconcile.go | 6 +++--- pkg/controller/eventing/trigger/reconcile.go | 2 +- 4 files changed, 25 insertions(+), 5 deletions(-) diff --git a/pkg/controller/eventing/broker/reconcile.go b/pkg/controller/eventing/broker/reconcile.go index 5837fcbfddb..95d602f31c6 100644 --- a/pkg/controller/eventing/broker/reconcile.go +++ b/pkg/controller/eventing/broker/reconcile.go @@ -85,7 +85,7 @@ func (r *reconciler) Reconcile(request reconcile.Request) (reconcile.Result, err } // Requeue if the resource is not ready: - return reconcile.Result{}, err + return reconcile.Result{}, reconcileErr } func (r *reconciler) reconcile(ctx context.Context, b *v1alpha1.Broker) error { diff --git a/pkg/controller/eventing/namespace/provider.go b/pkg/controller/eventing/namespace/provider.go index 01648c6918f..40602be6062 100644 --- a/pkg/controller/eventing/namespace/provider.go +++ b/pkg/controller/eventing/namespace/provider.go @@ -17,8 +17,10 @@ limitations under the License. package namespace import ( + "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" "go.uber.org/zap" "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/dynamic" "k8s.io/client-go/rest" "k8s.io/client-go/tools/record" @@ -68,10 +70,28 @@ func ProvideController(logger *zap.Logger) func(manager.Manager) (controller.Con return nil, err } + if err = c.Watch(&source.Kind{Type: &v1alpha1.Broker{}}, &handler.EnqueueRequestsFromMapFunc{ToRequests: &namespaceMapper{}}); err != nil { + return nil, err + } + return c, nil } } +type namespaceMapper struct {} +var _ handler.Mapper = &namespaceMapper{} + +func (namespaceMapper) Map(o handler.MapObject) []reconcile.Request { + return []reconcile.Request{ + { + NamespacedName: types.NamespacedName{ + Namespace: "", + Name: o.Meta.GetNamespace(), + }, + }, + } +} + func (r *reconciler) InjectClient(c client.Client) error { r.client = c return nil diff --git a/pkg/controller/eventing/namespace/reconcile.go b/pkg/controller/eventing/namespace/reconcile.go index 3185b04ca27..a9a8a064a64 100644 --- a/pkg/controller/eventing/namespace/reconcile.go +++ b/pkg/controller/eventing/namespace/reconcile.go @@ -31,7 +31,7 @@ import ( const ( defaultBroker = "default" - KnativeEventingAnnotation = "eventing.knative.dev/injection" + knativeEventingAnnotation = "eventing.knative.dev/injection" // Name of the corev1.Events emitted from the reconciliation process brokerCreated = "BrokerCreated" @@ -57,7 +57,7 @@ func (r *reconciler) Reconcile(request reconcile.Request) (reconcile.Result, err return reconcile.Result{}, err } - if ns.Annotations[KnativeEventingAnnotation] != "true" { + if ns.Annotations[knativeEventingAnnotation] != "true" { logging.FromContext(ctx).Debug("Not reconciling Namespace") return reconcile.Result{}, nil } @@ -72,7 +72,7 @@ func (r *reconciler) Reconcile(request reconcile.Request) (reconcile.Result, err } // Requeue if the resource is not ready: - return reconcile.Result{}, err + return reconcile.Result{}, reconcileErr } func (r *reconciler) reconcile(ctx context.Context, ns *corev1.Namespace) error { diff --git a/pkg/controller/eventing/trigger/reconcile.go b/pkg/controller/eventing/trigger/reconcile.go index 4e461d340b1..9cc17f8bd43 100644 --- a/pkg/controller/eventing/trigger/reconcile.go +++ b/pkg/controller/eventing/trigger/reconcile.go @@ -82,7 +82,7 @@ func (r *reconciler) Reconcile(request reconcile.Request) (reconcile.Result, err } // Requeue if the resource is not ready: - return reconcile.Result{}, err + return reconcile.Result{}, reconcileErr } func (r *reconciler) reconcile(ctx context.Context, t *v1alpha1.Trigger) error { From 4f803a2faeeb8dbe113f7c30a061d8967b6dc410 Mon Sep 17 00:00:00 2001 From: Adam Harwayne Date: Thu, 7 Feb 2019 11:02:13 -0800 Subject: [PATCH 026/221] Move the Logging package import and format. --- cmd/broker/filter/main.go | 2 +- cmd/broker/ingress/main.go | 15 ++++----- cmd/controller/main.go | 3 +- pkg/apis/eventing/v1alpha1/broker_defaults.go | 2 -- pkg/apis/eventing/v1alpha1/broker_types.go | 2 +- .../eventing/v1alpha1/broker_validation.go | 1 - pkg/apis/eventing/v1alpha1/trigger_types.go | 4 +-- pkg/broker/filter.go | 4 +-- pkg/controller/eventing/broker/provider.go | 10 +++--- pkg/controller/eventing/broker/reconcile.go | 20 ++++++------ .../eventing/broker/resources/filter.go | 27 ++++++++-------- .../eventing/broker/resources/ingress.go | 31 ++++++++++--------- pkg/controller/eventing/namespace/provider.go | 5 +-- .../eventing/namespace/reconcile.go | 11 ++++--- pkg/controller/eventing/trigger/reconcile.go | 9 +++--- 15 files changed, 73 insertions(+), 73 deletions(-) diff --git a/cmd/broker/filter/main.go b/cmd/broker/filter/main.go index f31dcee677f..0c39dec0550 100644 --- a/cmd/broker/filter/main.go +++ b/cmd/broker/filter/main.go @@ -18,6 +18,7 @@ package main import ( "flag" + eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" "github.com/knative/eventing/pkg/broker" "github.com/knative/eventing/pkg/provisioners" @@ -66,4 +67,3 @@ func main() { logger.Fatal("Manager.Start() returned an error", zap.Error(err)) } } - diff --git a/cmd/broker/ingress/main.go b/cmd/broker/ingress/main.go index 37b96da1412..1be24c382bb 100644 --- a/cmd/broker/ingress/main.go +++ b/cmd/broker/ingress/main.go @@ -20,12 +20,13 @@ import ( "context" "flag" "fmt" - "golang.org/x/sync/errgroup" "log" "net/http" "os" "time" + "golang.org/x/sync/errgroup" + eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" "github.com/knative/eventing/pkg/provisioners" "github.com/knative/pkg/signals" @@ -34,7 +35,6 @@ import ( "sigs.k8s.io/controller-runtime/pkg/manager" ) - var ( readTimeout = 1 * time.Minute writeTimeout = 1 * time.Minute @@ -59,7 +59,6 @@ func main() { logger.Fatal("Unable to add scheme", zap.Error(err)) } - c := getRequiredEnv("CHANNEL") h := NewHandler(logger, c) @@ -102,8 +101,8 @@ func getRequiredEnv(envKey string) string { // http.Handler that takes a single request in and fans it out to N other servers. type Handler struct { - receiver *provisioners.MessageReceiver - dispatcher *provisioners.MessageDispatcher + receiver *provisioners.MessageReceiver + dispatcher *provisioners.MessageDispatcher destination string logger *zap.Logger @@ -112,8 +111,8 @@ type Handler struct { // NewHandler creates a new fanout.Handler. func NewHandler(logger *zap.Logger, destination string) *Handler { handler := &Handler{ - logger: logger, - dispatcher: provisioners.NewMessageDispatcher(logger.Sugar()), + logger: logger, + dispatcher: provisioners.NewMessageDispatcher(logger.Sugar()), destination: fmt.Sprintf("http://%s", destination), } // The receiver function needs to point back at the handler itself, so set it up after @@ -143,5 +142,3 @@ func (f *Handler) dispatch(msg *provisioners.Message) error { } return err } - - diff --git a/cmd/controller/main.go b/cmd/controller/main.go index 5eee4da37d1..966139ae6e6 100644 --- a/cmd/controller/main.go +++ b/cmd/controller/main.go @@ -19,12 +19,13 @@ package main import ( "context" "flag" - "github.com/knative/eventing/pkg/controller/eventing/namespace" "log" "net/http" "os" "time" + "github.com/knative/eventing/pkg/controller/eventing/namespace" + "github.com/knative/eventing/pkg/controller/eventing/trigger" "github.com/knative/eventing/pkg/controller/eventing/broker" diff --git a/pkg/apis/eventing/v1alpha1/broker_defaults.go b/pkg/apis/eventing/v1alpha1/broker_defaults.go index 890e4fbecf0..2efdd4e3f79 100644 --- a/pkg/apis/eventing/v1alpha1/broker_defaults.go +++ b/pkg/apis/eventing/v1alpha1/broker_defaults.go @@ -27,5 +27,3 @@ func (b *Broker) SetDefaults() { func (bs *BrokerSpec) SetDefaults(brokerName string) { // None } - - diff --git a/pkg/apis/eventing/v1alpha1/broker_types.go b/pkg/apis/eventing/v1alpha1/broker_types.go index fa0ba9b7c93..b50cd43101a 100644 --- a/pkg/apis/eventing/v1alpha1/broker_types.go +++ b/pkg/apis/eventing/v1alpha1/broker_types.go @@ -58,7 +58,7 @@ type BrokerSpec struct { // +optional DeprecatedGeneration int64 `json:"generation,omitempty"` - ChannelTemplate *ChannelSpec `json:"channelTemplate,omitempty"` + ChannelTemplate *ChannelSpec `json:"channelTemplate,omitempty"` } var brokerCondSet = duckv1alpha1.NewLivingConditionSet(BrokerConditionIngress, BrokerConditionChannel, BrokerConditionFilter, BrokerConditionAddressable) diff --git a/pkg/apis/eventing/v1alpha1/broker_validation.go b/pkg/apis/eventing/v1alpha1/broker_validation.go index c7954c26d15..028b8db11f6 100644 --- a/pkg/apis/eventing/v1alpha1/broker_validation.go +++ b/pkg/apis/eventing/v1alpha1/broker_validation.go @@ -28,7 +28,6 @@ func (bs *BrokerSpec) Validate() *apis.FieldError { return nil } - func (b *Broker) CheckImmutableFields(og apis.Immutable) *apis.FieldError { return nil } diff --git a/pkg/apis/eventing/v1alpha1/trigger_types.go b/pkg/apis/eventing/v1alpha1/trigger_types.go index 3e2c1d0c654..86b7c121bf6 100644 --- a/pkg/apis/eventing/v1alpha1/trigger_types.go +++ b/pkg/apis/eventing/v1alpha1/trigger_types.go @@ -58,8 +58,8 @@ type TriggerSpec struct { // +optional DeprecatedGeneration int64 `json:"generation,omitempty"` - Broker string `json:"broker,omitempty"` - Subscriber *SubscriberSpec `json:"subscriber,omitempty"` + Broker string `json:"broker,omitempty"` + Subscriber *SubscriberSpec `json:"subscriber,omitempty"` Type string `json:"type,omitempty"` Source string `json:"source,omitempty"` diff --git a/pkg/broker/filter.go b/pkg/broker/filter.go index a0e467dd942..60e2ae3d6ac 100644 --- a/pkg/broker/filter.go +++ b/pkg/broker/filter.go @@ -44,8 +44,8 @@ type Receiver struct { // Start()ing the returned MessageReceiver. func New(logger *zap.Logger, client client.Client) (*Receiver, manager.Runnable) { r := &Receiver{ - logger: logger, - client: client, + logger: logger, + client: client, dispatcher: provisioners.NewMessageDispatcher(logger.Sugar()), } return r, r.newMessageReceiver() diff --git a/pkg/controller/eventing/broker/provider.go b/pkg/controller/eventing/broker/provider.go index 5d94c8cbcfb..3136269a5df 100644 --- a/pkg/controller/eventing/broker/provider.go +++ b/pkg/controller/eventing/broker/provider.go @@ -46,8 +46,8 @@ type reconciler struct { ingressImage string ingressServiceAccountName string - filterImage string - filterServiceAccountName string + filterImage string + filterServiceAccountName string } // Verify the struct implements reconcile.Reconciler @@ -62,10 +62,10 @@ func ProvideController(logger *zap.Logger, ingressImage, ingressServiceAccount, recorder: mgr.GetRecorder(controllerAgentName), logger: logger, - ingressImage: ingressImage, + ingressImage: ingressImage, ingressServiceAccountName: ingressServiceAccount, - filterImage: filterImage, - filterServiceAccountName: filterServiceAccount, + filterImage: filterImage, + filterServiceAccountName: filterServiceAccount, }, }) if err != nil { diff --git a/pkg/controller/eventing/broker/reconcile.go b/pkg/controller/eventing/broker/reconcile.go index 95d602f31c6..f26b9ab2fb8 100644 --- a/pkg/controller/eventing/broker/reconcile.go +++ b/pkg/controller/eventing/broker/reconcile.go @@ -19,15 +19,16 @@ package broker import ( "context" "fmt" + + "github.com/knative/eventing/contrib/gcppubsub/pkg/util/logging" "github.com/knative/eventing/pkg/controller" - "k8s.io/api/apps/v1" + v1 "k8s.io/api/apps/v1" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime/schema" "github.com/knative/eventing/pkg/controller/eventing/broker/resources" - "github.com/knative/eventing/pkg/provisioners/gcppubsub/util/logging" "go.uber.org/zap" "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" @@ -131,7 +132,6 @@ func (r *reconciler) reconcile(ctx context.Context, b *v1alpha1.Broker) error { return err } - svc, err := r.reconcileIngressService(ctx, b) if err != nil { logging.FromContext(ctx).Error("Problem reconciling ingress Service", zap.Error(err)) @@ -265,12 +265,12 @@ func newChannel(b *v1alpha1.Broker) *v1alpha1.Channel { ObjectMeta: metav1.ObjectMeta{ Namespace: b.Namespace, GenerateName: fmt.Sprintf("%s-broker-", b.Name), - Labels: ChannelLabels(b), + Labels: ChannelLabels(b), OwnerReferences: []metav1.OwnerReference{ *metav1.NewControllerRef(b, schema.GroupVersionKind{ Group: v1alpha1.SchemeGroupVersion.Group, Version: v1alpha1.SchemeGroupVersion.Version, - Kind: "Broker", + Kind: "Broker", }), }, }, @@ -280,7 +280,7 @@ func newChannel(b *v1alpha1.Broker) *v1alpha1.Channel { func ChannelLabels(b *v1alpha1.Broker) map[string]string { return map[string]string{ - "eventing.knative.dev/broker": b.Name, + "eventing.knative.dev/broker": b.Name, "eventing.knative.dev/brokerEverything": "true", } } @@ -344,10 +344,10 @@ func (r *reconciler) reconcileService(ctx context.Context, svc *corev1.Service) func (r *reconciler) reconcileIngressDeployment(ctx context.Context, b *v1alpha1.Broker, c *v1alpha1.Channel) (*v1.Deployment, error) { expected, err := resources.MakeIngress(&resources.IngressArgs{ - Broker: b, - Image: r.ingressImage, - ServiceAccountName: r.ingressServiceAccountName, - ChannelAddress: c.Status.Address.Hostname, + Broker: b, + Image: r.ingressImage, + ServiceAccountName: r.ingressServiceAccountName, + ChannelAddress: c.Status.Address.Hostname, }) if err != nil { return nil, err diff --git a/pkg/controller/eventing/broker/resources/filter.go b/pkg/controller/eventing/broker/resources/filter.go index dcb330c5570..4de9be6d0df 100644 --- a/pkg/controller/eventing/broker/resources/filter.go +++ b/pkg/controller/eventing/broker/resources/filter.go @@ -18,6 +18,7 @@ package resources import ( "fmt" + appsv1 "k8s.io/api/apps/v1" "k8s.io/apimachinery/pkg/util/intstr" @@ -28,9 +29,9 @@ import ( ) type FilterArgs struct { - Broker *eventingv1alpha1.Broker - Image string - ServiceAccountName string + Broker *eventingv1alpha1.Broker + Image string + ServiceAccountName string } func MakeFilterDeployment(args *FilterArgs) (*appsv1.Deployment, error) { @@ -42,7 +43,7 @@ func MakeFilterDeployment(args *FilterArgs) (*appsv1.Deployment, error) { *metav1.NewControllerRef(args.Broker, schema.GroupVersionKind{ Group: eventingv1alpha1.SchemeGroupVersion.Group, Version: eventingv1alpha1.SchemeGroupVersion.Version, - Kind: "Broker", + Kind: "Broker", }), }, }, @@ -62,10 +63,10 @@ func MakeFilterDeployment(args *FilterArgs) (*appsv1.Deployment, error) { Containers: []corev1.Container{ { Image: args.Image, - Name: "filter", + Name: "filter", Env: []corev1.EnvVar{ { - Name: "BROKER", + Name: "BROKER", Value: args.Broker.Name, }, }, @@ -80,14 +81,14 @@ func MakeFilterDeployment(args *FilterArgs) (*appsv1.Deployment, error) { func MakeFilterService(b *eventingv1alpha1.Broker) *corev1.Service { return &corev1.Service{ ObjectMeta: metav1.ObjectMeta{ - Namespace: b.Namespace, - Name: fmt.Sprintf("%s-broker-filter", b.Name), - Labels: filterLabels(b), + Namespace: b.Namespace, + Name: fmt.Sprintf("%s-broker-filter", b.Name), + Labels: filterLabels(b), OwnerReferences: []metav1.OwnerReference{ *metav1.NewControllerRef(b, schema.GroupVersionKind{ Group: eventingv1alpha1.SchemeGroupVersion.Group, Version: eventingv1alpha1.SchemeGroupVersion.Version, - Kind: "Broker", + Kind: "Broker", }), }, }, @@ -95,8 +96,8 @@ func MakeFilterService(b *eventingv1alpha1.Broker) *corev1.Service { Selector: filterLabels(b), Ports: []corev1.ServicePort{ { - Name: "http", - Port: 80, + Name: "http", + Port: 80, TargetPort: intstr.FromInt(8080), }, }, @@ -106,7 +107,7 @@ func MakeFilterService(b *eventingv1alpha1.Broker) *corev1.Service { func filterLabels(b *eventingv1alpha1.Broker) map[string]string { return map[string]string{ - "eventing.knative.dev/broker": b.Name, + "eventing.knative.dev/broker": b.Name, "eventing.knative.dev/brokerRole": "filter", } } diff --git a/pkg/controller/eventing/broker/resources/ingress.go b/pkg/controller/eventing/broker/resources/ingress.go index 4f6933116f9..a5444b5cf68 100644 --- a/pkg/controller/eventing/broker/resources/ingress.go +++ b/pkg/controller/eventing/broker/resources/ingress.go @@ -18,6 +18,7 @@ package resources import ( "fmt" + appsv1 "k8s.io/api/apps/v1" "k8s.io/apimachinery/pkg/util/intstr" @@ -28,10 +29,10 @@ import ( ) type IngressArgs struct { - Broker *eventingv1alpha1.Broker - Image string - ServiceAccountName string - ChannelAddress string + Broker *eventingv1alpha1.Broker + Image string + ServiceAccountName string + ChannelAddress string } func MakeIngress(args *IngressArgs) (*appsv1.Deployment, error) { @@ -43,7 +44,7 @@ func MakeIngress(args *IngressArgs) (*appsv1.Deployment, error) { *metav1.NewControllerRef(args.Broker, schema.GroupVersionKind{ Group: eventingv1alpha1.SchemeGroupVersion.Group, Version: eventingv1alpha1.SchemeGroupVersion.Version, - Kind: "Broker", + Kind: "Broker", }), }, }, @@ -63,14 +64,14 @@ func MakeIngress(args *IngressArgs) (*appsv1.Deployment, error) { Containers: []corev1.Container{ { Image: args.Image, - Name: "ingress", + Name: "ingress", Env: []corev1.EnvVar{ { - Name: "FILTER", + Name: "FILTER", Value: "", // TODO Add one. }, { - Name: "CHANNEL", + Name: "CHANNEL", Value: args.ChannelAddress, }, }, @@ -85,14 +86,14 @@ func MakeIngress(args *IngressArgs) (*appsv1.Deployment, error) { func MakeIngressService(b *eventingv1alpha1.Broker) *corev1.Service { return &corev1.Service{ ObjectMeta: metav1.ObjectMeta{ - Namespace: b.Namespace, - Name: fmt.Sprintf("%s-broker", b.Name), - Labels: ingressLabels(b), + Namespace: b.Namespace, + Name: fmt.Sprintf("%s-broker", b.Name), + Labels: ingressLabels(b), OwnerReferences: []metav1.OwnerReference{ *metav1.NewControllerRef(b, schema.GroupVersionKind{ Group: eventingv1alpha1.SchemeGroupVersion.Group, Version: eventingv1alpha1.SchemeGroupVersion.Version, - Kind: "Broker", + Kind: "Broker", }), }, }, @@ -100,8 +101,8 @@ func MakeIngressService(b *eventingv1alpha1.Broker) *corev1.Service { Selector: ingressLabels(b), Ports: []corev1.ServicePort{ { - Name: "http", - Port: 80, + Name: "http", + Port: 80, TargetPort: intstr.FromInt(8080), }, }, @@ -111,7 +112,7 @@ func MakeIngressService(b *eventingv1alpha1.Broker) *corev1.Service { func ingressLabels(b *eventingv1alpha1.Broker) map[string]string { return map[string]string{ - "eventing.knative.dev/broker": b.Name, + "eventing.knative.dev/broker": b.Name, "eventing.knative.dev/brokerRole": "ingress", } } diff --git a/pkg/controller/eventing/namespace/provider.go b/pkg/controller/eventing/namespace/provider.go index 40602be6062..2107c50fb5d 100644 --- a/pkg/controller/eventing/namespace/provider.go +++ b/pkg/controller/eventing/namespace/provider.go @@ -19,7 +19,7 @@ package namespace import ( "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" "go.uber.org/zap" - "k8s.io/api/core/v1" + v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/dynamic" "k8s.io/client-go/rest" @@ -78,7 +78,8 @@ func ProvideController(logger *zap.Logger) func(manager.Manager) (controller.Con } } -type namespaceMapper struct {} +type namespaceMapper struct{} + var _ handler.Mapper = &namespaceMapper{} func (namespaceMapper) Map(o handler.MapObject) []reconcile.Request { diff --git a/pkg/controller/eventing/namespace/reconcile.go b/pkg/controller/eventing/namespace/reconcile.go index a9a8a064a64..cc2b2913010 100644 --- a/pkg/controller/eventing/namespace/reconcile.go +++ b/pkg/controller/eventing/namespace/reconcile.go @@ -18,8 +18,9 @@ package namespace import ( "context" + + "github.com/knative/eventing/contrib/gcppubsub/pkg/util/logging" "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" - "github.com/knative/eventing/pkg/provisioners/gcppubsub/util/logging" "go.uber.org/zap" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" @@ -30,7 +31,7 @@ import ( ) const ( - defaultBroker = "default" + defaultBroker = "default" knativeEventingAnnotation = "eventing.knative.dev/injection" // Name of the corev1.Events emitted from the reconciliation process @@ -121,9 +122,9 @@ func (r *reconciler) reconcileBroker(ctx context.Context, ns *corev1.Namespace) func newBroker(ns *corev1.Namespace) *v1alpha1.Broker { return &v1alpha1.Broker{ ObjectMeta: metav1.ObjectMeta{ - Namespace: ns.Name, - Name: defaultBroker, - Labels: brokerLabels(), + Namespace: ns.Name, + Name: defaultBroker, + Labels: brokerLabels(), }, } } diff --git a/pkg/controller/eventing/trigger/reconcile.go b/pkg/controller/eventing/trigger/reconcile.go index 9cc17f8bd43..3652f34ae57 100644 --- a/pkg/controller/eventing/trigger/reconcile.go +++ b/pkg/controller/eventing/trigger/reconcile.go @@ -19,11 +19,12 @@ package trigger import ( "context" "fmt" + + "github.com/knative/eventing/contrib/gcppubsub/pkg/util/logging" "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" "github.com/knative/eventing/pkg/controller" "github.com/knative/eventing/pkg/controller/eventing/broker" "github.com/knative/eventing/pkg/controller/eventing/subscription" - "github.com/knative/eventing/pkg/provisioners/gcppubsub/util/logging" istiov1alpha3 "github.com/knative/pkg/apis/istio/v1alpha3" "go.uber.org/zap" corev1 "k8s.io/api/core/v1" @@ -481,13 +482,13 @@ func makeSubscription(t *v1alpha1.Trigger, c *v1alpha1.Channel, svc *corev1.Serv Spec: v1alpha1.SubscriptionSpec{ Channel: corev1.ObjectReference{ APIVersion: v1alpha1.SchemeGroupVersion.String(), - Kind: "Channel", + Kind: "Channel", Name: c.Name, }, Subscriber: &v1alpha1.SubscriberSpec{ Ref: &corev1.ObjectReference{ APIVersion: "v1", - Kind: "Service", + Kind: "Service", Name: svc.Name, }, }, @@ -495,7 +496,7 @@ func makeSubscription(t *v1alpha1.Trigger, c *v1alpha1.Channel, svc *corev1.Serv Reply: &v1alpha1.ReplyStrategy{ Channel: &corev1.ObjectReference{ APIVersion: v1alpha1.SchemeGroupVersion.String(), - Kind: "Channel", + Kind: "Channel", Name: c.Name, }, }, From eec0f8d70001e3903c364df72ffc612553648c2f Mon Sep 17 00:00:00 2001 From: nachocano Date: Thu, 7 Feb 2019 16:31:22 -0800 Subject: [PATCH 027/221] Updating after review comments. Only doing exact header matching. In a follow up PR, I plan to include matching of expressions. It turns our that they are somewhat more involved than expected. --- .../eventing/v1alpha1/trigger_defaults.go | 11 ++---- pkg/apis/eventing/v1alpha1/trigger_types.go | 10 ++++-- .../eventing/v1alpha1/trigger_validation.go | 2 +- .../v1alpha1/zz_generated.deepcopy.go | 36 +++++++++++++++---- pkg/broker/filter.go | 20 +++++------ t2.yaml | 12 +++---- 6 files changed, 55 insertions(+), 36 deletions(-) diff --git a/pkg/apis/eventing/v1alpha1/trigger_defaults.go b/pkg/apis/eventing/v1alpha1/trigger_defaults.go index 334be735fa6..1869815a849 100644 --- a/pkg/apis/eventing/v1alpha1/trigger_defaults.go +++ b/pkg/apis/eventing/v1alpha1/trigger_defaults.go @@ -16,8 +16,6 @@ limitations under the License. package v1alpha1 -import v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - func (t *Trigger) SetDefaults() { t.Spec.SetDefaults() } @@ -26,11 +24,8 @@ func (ts *TriggerSpec) SetDefaults() { if ts.Broker == "" { ts.Broker = "default" } - // Make an empty LabelSelector so that we allow everything. - if ts.Filters == nil { - ts.Filters = &v1.LabelSelector{ - MatchLabels: make(map[string]string, 0), - MatchExpressions: make([]v1.LabelSelectorRequirement, 0), - } + // Make empty filter selector so that we allow everything. + if ts.Filter == nil { + ts.Filter = &FilterSelector{map[string]string{}} } } diff --git a/pkg/apis/eventing/v1alpha1/trigger_types.go b/pkg/apis/eventing/v1alpha1/trigger_types.go index 303f57cb8d2..39e199ea6cf 100644 --- a/pkg/apis/eventing/v1alpha1/trigger_types.go +++ b/pkg/apis/eventing/v1alpha1/trigger_types.go @@ -58,10 +58,16 @@ type TriggerSpec struct { // +optional DeprecatedGeneration int64 `json:"generation,omitempty"` - Broker string `json:"broker,omitempty"` + Broker string `json:"broker,omitempty"` + + // +optional + Filter *FilterSelector `json:"filter,omitempty"` + Subscriber *SubscriberSpec `json:"subscriber,omitempty"` +} - Filters *metav1.LabelSelector `json:"filters,omitempty"` +type FilterSelector struct { + Headers map[string]string `json:"headers,omitempty" protobuf:"bytes,1,rep,name=headers"` } var triggerCondSet = duckv1alpha1.NewLivingConditionSet(TriggerConditionBrokerExists, TriggerConditionKubernetesService, TriggerConditionVirtualService, TriggerConditionSubscribed) diff --git a/pkg/apis/eventing/v1alpha1/trigger_validation.go b/pkg/apis/eventing/v1alpha1/trigger_validation.go index e93b2f60195..42057cf9bef 100644 --- a/pkg/apis/eventing/v1alpha1/trigger_validation.go +++ b/pkg/apis/eventing/v1alpha1/trigger_validation.go @@ -32,7 +32,7 @@ func (ts *TriggerSpec) Validate() *apis.FieldError { errs = errs.Also(fe) } - if ts.Filters == nil { + if ts.Filter == nil { fe := apis.ErrMissingField("filters") errs = errs.Also(fe) } diff --git a/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go index 79fb64c6e3a..167f6d00748 100644 --- a/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go @@ -24,7 +24,6 @@ import ( apis_duck_v1alpha1 "github.com/knative/eventing/pkg/apis/duck/v1alpha1" duck_v1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" v1 "k8s.io/api/core/v1" - meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" ) @@ -375,6 +374,29 @@ func (in *ClusterChannelProvisionerStatus) DeepCopy() *ClusterChannelProvisioner return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FilterSelector) DeepCopyInto(out *FilterSelector) { + *out = *in + if in.Headers != nil { + in, out := &in.Headers, &out.Headers + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FilterSelector. +func (in *FilterSelector) DeepCopy() *FilterSelector { + if in == nil { + return nil + } + out := new(FilterSelector) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ReplyStrategy) DeepCopyInto(out *ReplyStrategy) { *out = *in @@ -634,21 +656,21 @@ func (in *TriggerList) DeepCopyObject() runtime.Object { // 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.Subscriber != nil { - in, out := &in.Subscriber, &out.Subscriber + if in.Filter != nil { + in, out := &in.Filter, &out.Filter if *in == nil { *out = nil } else { - *out = new(SubscriberSpec) + *out = new(FilterSelector) (*in).DeepCopyInto(*out) } } - if in.Filters != nil { - in, out := &in.Filters, &out.Filters + if in.Subscriber != nil { + in, out := &in.Subscriber, &out.Subscriber if *in == nil { *out = nil } else { - *out = new(meta_v1.LabelSelector) + *out = new(SubscriberSpec) (*in).DeepCopyInto(*out) } } diff --git a/pkg/broker/filter.go b/pkg/broker/filter.go index 2e80d8ef31e..78002d23b36 100644 --- a/pkg/broker/filter.go +++ b/pkg/broker/filter.go @@ -20,13 +20,10 @@ import ( "context" "errors" - "k8s.io/apimachinery/pkg/labels" - - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" "github.com/knative/eventing/pkg/provisioners" "go.uber.org/zap" + "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/manager" @@ -102,13 +99,12 @@ func (r *Receiver) getTrigger(ctx context.Context, ref provisioners.ChannelRefer } func (r *Receiver) shouldSendMessage(t *eventingv1alpha1.TriggerSpec, m *provisioners.Message) bool { - // TODO, this conversion to selector should be done only once, possibly upon creation of the trigger - // in case the filters are immutable - selector, err := v1.LabelSelectorAsSelector(t.Filters) - if err != nil { - r.logger.Error("Invalid label selector for filter", zap.Error(err)) - return false + // This conversion to selector should be done only once, possibly upon creation of the trigger + // in case the filters are immutable. All validations should be performed then. + selector := labels.SelectorFromValidatedSet(labels.Set(t.Filter.Headers)) + matched := selector.Matches(labels.Set(m.Headers)) + if !matched { + r.logger.Debug("Selector did not match message headers", zap.String("selector", selector.String()), zap.Any("headers", m.Headers)) } - l := labels.Set(m.Headers) - return selector.Matches(l) + return matched } diff --git a/t2.yaml b/t2.yaml index b912ba497a4..02b2f7ba64d 100644 --- a/t2.yaml +++ b/t2.yaml @@ -3,14 +3,14 @@ kind: Trigger metadata: name: t spec: + # Our Cloud Event parsing library seems to have a bug and forces to put type and source in double + # quotes (as it thinks the actual value is `"foo"`, not `foo`). + filter: + headers: + Ce-Eventtype: '"com.example.someevent"' + Ce-Source: '"/mycontext/subcontext"' subscriber: ref: apiVersion: serving.knative.dev/v1alpha1 kind: Service name: message-dumper - # Our Cloud Event parsing library seems to have a bug and forces to put type and source in double - # quotes (as it thinks the actual value is `"foo"`, not `foo`). - filters: - matchLabels: - Ce-Eventtype: com.example.someevent - Ce-Source: mycontext From 34d42e0e1f68ff5646041f4e9c3acccd4d0c5ac8 Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Thu, 7 Feb 2019 23:38:59 -0800 Subject: [PATCH 028/221] Adding filtering expressions. Currently using LabelSelectors without validations. Using reflection to set some unexposed fields for now. --- Gopkg.lock | 1 + .../eventing/v1alpha1/trigger_defaults.go | 5 +- pkg/apis/eventing/v1alpha1/trigger_types.go | 3 +- .../v1alpha1/zz_generated.deepcopy.go | 8 +++ pkg/broker/filter.go | 55 +++++++++++++++++-- t3.yaml | 17 ++++++ 6 files changed, 82 insertions(+), 7 deletions(-) create mode 100644 t3.yaml diff --git a/Gopkg.lock b/Gopkg.lock index bf228ba34d9..96b06a0de20 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -1271,6 +1271,7 @@ "k8s.io/apimachinery/pkg/runtime", "k8s.io/apimachinery/pkg/runtime/schema", "k8s.io/apimachinery/pkg/runtime/serializer", + "k8s.io/apimachinery/pkg/selection", "k8s.io/apimachinery/pkg/types", "k8s.io/apimachinery/pkg/util/intstr", "k8s.io/apimachinery/pkg/util/sets", diff --git a/pkg/apis/eventing/v1alpha1/trigger_defaults.go b/pkg/apis/eventing/v1alpha1/trigger_defaults.go index 1869815a849..d996d5ea30d 100644 --- a/pkg/apis/eventing/v1alpha1/trigger_defaults.go +++ b/pkg/apis/eventing/v1alpha1/trigger_defaults.go @@ -16,6 +16,8 @@ limitations under the License. package v1alpha1 +import v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + func (t *Trigger) SetDefaults() { t.Spec.SetDefaults() } @@ -26,6 +28,7 @@ func (ts *TriggerSpec) SetDefaults() { } // Make empty filter selector so that we allow everything. if ts.Filter == nil { - ts.Filter = &FilterSelector{map[string]string{}} + ts.Filter = &FilterSelector{map[string]string{}, + []v1.LabelSelectorRequirement{}} } } diff --git a/pkg/apis/eventing/v1alpha1/trigger_types.go b/pkg/apis/eventing/v1alpha1/trigger_types.go index 39e199ea6cf..11b86e52b23 100644 --- a/pkg/apis/eventing/v1alpha1/trigger_types.go +++ b/pkg/apis/eventing/v1alpha1/trigger_types.go @@ -67,7 +67,8 @@ type TriggerSpec struct { } type FilterSelector struct { - Headers map[string]string `json:"headers,omitempty" protobuf:"bytes,1,rep,name=headers"` + Headers map[string]string `json:"headers,omitempty" protobuf:"bytes,1,rep,name=headers"` + HeaderExpressions []metav1.LabelSelectorRequirement `json:"headerExpressions,omitempty" protobuf:"bytes,2,rep,name=headerExpressions"` } var triggerCondSet = duckv1alpha1.NewLivingConditionSet(TriggerConditionBrokerExists, TriggerConditionKubernetesService, TriggerConditionVirtualService, TriggerConditionSubscribed) diff --git a/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go index 167f6d00748..2e9b4cc6e90 100644 --- a/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go @@ -24,6 +24,7 @@ import ( apis_duck_v1alpha1 "github.com/knative/eventing/pkg/apis/duck/v1alpha1" duck_v1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" v1 "k8s.io/api/core/v1" + meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" ) @@ -384,6 +385,13 @@ func (in *FilterSelector) DeepCopyInto(out *FilterSelector) { (*out)[key] = val } } + if in.HeaderExpressions != nil { + in, out := &in.HeaderExpressions, &out.HeaderExpressions + *out = make([]meta_v1.LabelSelectorRequirement, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } return } diff --git a/pkg/broker/filter.go b/pkg/broker/filter.go index 78002d23b36..eaeb633525f 100644 --- a/pkg/broker/filter.go +++ b/pkg/broker/filter.go @@ -19,6 +19,12 @@ package broker import ( "context" "errors" + "fmt" + "reflect" + "unsafe" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/selection" eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" "github.com/knative/eventing/pkg/provisioners" @@ -29,10 +35,6 @@ import ( "sigs.k8s.io/controller-runtime/pkg/manager" ) -const ( - Any = "Any" -) - // Receiver parses Cloud Events and sends them to GCP PubSub. type Receiver struct { logger *zap.Logger @@ -101,10 +103,53 @@ func (r *Receiver) getTrigger(ctx context.Context, ref provisioners.ChannelRefer func (r *Receiver) shouldSendMessage(t *eventingv1alpha1.TriggerSpec, m *provisioners.Message) bool { // This conversion to selector should be done only once, possibly upon creation of the trigger // in case the filters are immutable. All validations should be performed then. - selector := labels.SelectorFromValidatedSet(labels.Set(t.Filter.Headers)) + selector, err := r.buildSelector(t) + if err != nil { + r.logger.Error("Invalid selector for trigger spec", zap.Any("triggerSpec", t)) + return false + } matched := selector.Matches(labels.Set(m.Headers)) if !matched { r.logger.Debug("Selector did not match message headers", zap.String("selector", selector.String()), zap.Any("headers", m.Headers)) } return matched } + +func (r *Receiver) buildSelector(ts *eventingv1alpha1.TriggerSpec) (labels.Selector, error) { + // Avoid validation of keys and values, otherwise we cannot use LabelSelectors. + // Eventually, we will need to create our own Selector implementation with our own Requirement struct. + selector := labels.SelectorFromValidatedSet(labels.Set(ts.Filter.Headers)) + for _, expr := range ts.Filter.HeaderExpressions { + var op selection.Operator + switch expr.Operator { + case v1.LabelSelectorOpIn: + op = selection.In + case v1.LabelSelectorOpNotIn: + op = selection.NotIn + case v1.LabelSelectorOpExists: + op = selection.Exists + case v1.LabelSelectorOpDoesNotExist: + op = selection.DoesNotExist + default: + return nil, fmt.Errorf("%q is not a valid filter selector operator", expr.Operator) + } + // Hack to set Requirement's unexposed fields to easily support expressions using k8s LabelSelectors. + // We should change this once we agree on a filter API. + r := labels.Requirement{} + rr := reflect.ValueOf(&r).Elem() + // Setting key + rrKey := rr.FieldByName("key") + rrKey = reflect.NewAt(rrKey.Type(), unsafe.Pointer(rrKey.UnsafeAddr())).Elem() + rrKey.SetString(expr.Key) + // Setting operator + rrOperator := rr.FieldByName("operator") + rrOperator = reflect.NewAt(rrOperator.Type(), unsafe.Pointer(rrOperator.UnsafeAddr())).Elem() + rrOperator.Set(reflect.ValueOf(op)) + // Setting strValues + rrStrValues := rr.FieldByName("strValues") + rrStrValues = reflect.NewAt(rrStrValues.Type(), unsafe.Pointer(rrStrValues.UnsafeAddr())).Elem() + rrStrValues.Set(reflect.ValueOf(expr.Values)) + selector = selector.Add(r) + } + return selector, nil +} diff --git a/t3.yaml b/t3.yaml new file mode 100644 index 00000000000..0ed3e969020 --- /dev/null +++ b/t3.yaml @@ -0,0 +1,17 @@ +apiVersion: eventing.knative.dev/v1alpha1 +kind: Trigger +metadata: + name: t +spec: + # Our Cloud Event parsing library seems to have a bug and forces to put type and source in double + # quotes (as it thinks the actual value is `"foo"`, not `foo`). + filter: + headers: + Ce-Source: '"/mycontext/subcontext"' + headerExpressions: + - {key: Ce-Eventtype, operator: In, values: ['"com.example.someevent"', '"com.example.someevent1"']} + subscriber: + ref: + apiVersion: serving.knative.dev/v1alpha1 + kind: Service + name: message-dumper From ad4e6f55d917a039d159cf529bcce3619d6eb960 Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Mon, 11 Feb 2019 10:47:02 -0800 Subject: [PATCH 029/221] Changes to compile --- pkg/broker/filter_test.go | 9 ++++----- pkg/provisioners/broker/reconcile.go | 7 ++++--- pkg/provisioners/trigger/reconcile.go | 9 +++++---- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/pkg/broker/filter_test.go b/pkg/broker/filter_test.go index 77d9b0d0923..2dead920105 100644 --- a/pkg/broker/filter_test.go +++ b/pkg/broker/filter_test.go @@ -23,12 +23,12 @@ import ( "strings" "testing" - "github.com/knative/eventing/pkg/provisioners/gcppubsub/util" + "github.com/knative/eventing/contrib/gcppubsub/pkg/util" eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" "k8s.io/client-go/kubernetes/scheme" - "github.com/knative/eventing/pkg/provisioners/gcppubsub/util/fakepubsub" + "github.com/knative/eventing/contrib/gcppubsub/pkg/util/fakepubsub" "go.uber.org/zap" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -36,7 +36,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client/fake" - "github.com/knative/eventing/pkg/provisioners/gcppubsub/util/testcreds" + "github.com/knative/eventing/contrib/gcppubsub/pkg/util/testcreds" ) const ( @@ -130,8 +130,7 @@ func TestReceiver(t *testing.T) { t.Run(n, func(t *testing.T) { mr, _ := New( zap.NewNop(), - fake.NewFakeClient(tc.initialState...), - fakepubsub.Creator(tc.pubSubData)) + fake.NewFakeClient(tc.initialState...)) resp := httptest.NewRecorder() req := httptest.NewRequest("POST", "/", strings.NewReader(validMessage)) req.Host = "test-channel.test-namespace.channels.cluster.local" diff --git a/pkg/provisioners/broker/reconcile.go b/pkg/provisioners/broker/reconcile.go index f26b9ab2fb8..7abd4cf8d6e 100644 --- a/pkg/provisioners/broker/reconcile.go +++ b/pkg/provisioners/broker/reconcile.go @@ -20,14 +20,15 @@ import ( "context" "fmt" + "github.com/knative/eventing/pkg/reconciler/names" + "github.com/knative/eventing/contrib/gcppubsub/pkg/util/logging" - "github.com/knative/eventing/pkg/controller" v1 "k8s.io/api/apps/v1" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime/schema" - "github.com/knative/eventing/pkg/controller/eventing/broker/resources" + "github.com/knative/eventing/pkg/provisioners/broker/resources" "go.uber.org/zap" @@ -138,7 +139,7 @@ func (r *reconciler) reconcile(ctx context.Context, b *v1alpha1.Broker) error { return err } b.Status.MarkIngressReady() - b.Status.SetAddress(controller.ServiceHostName(svc.Name, svc.Namespace)) + b.Status.SetAddress(names.ServiceHostName(svc.Name, svc.Namespace)) return nil } diff --git a/pkg/provisioners/trigger/reconcile.go b/pkg/provisioners/trigger/reconcile.go index 3652f34ae57..668742d1308 100644 --- a/pkg/provisioners/trigger/reconcile.go +++ b/pkg/provisioners/trigger/reconcile.go @@ -20,11 +20,12 @@ import ( "context" "fmt" + "github.com/knative/eventing/pkg/reconciler/names" + "github.com/knative/eventing/contrib/gcppubsub/pkg/util/logging" "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" - "github.com/knative/eventing/pkg/controller" - "github.com/knative/eventing/pkg/controller/eventing/broker" - "github.com/knative/eventing/pkg/controller/eventing/subscription" + "github.com/knative/eventing/pkg/provisioners/broker" + "github.com/knative/eventing/pkg/reconciler/v1alpha1/subscription" istiov1alpha3 "github.com/knative/pkg/apis/istio/v1alpha3" "go.uber.org/zap" corev1 "k8s.io/api/core/v1" @@ -383,7 +384,7 @@ func newVirtualService(t *v1alpha1.Trigger, svc *corev1.Service) *istiov1alpha3. }, Spec: istiov1alpha3.VirtualServiceSpec{ Hosts: []string{ - controller.ServiceHostName(svc.Name, svc.Namespace), + names.ServiceHostName(svc.Name, svc.Namespace), }, Http: []istiov1alpha3.HTTPRoute{{ Rewrite: &istiov1alpha3.HTTPRewrite{ From bc519d8986f2c060f205c0932f9805adbb0ba497 Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Mon, 11 Feb 2019 11:01:26 -0800 Subject: [PATCH 030/221] moving filter --- pkg/{ => provisioners}/broker/filter.go | 0 pkg/{ => provisioners}/broker/filter_test.go | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename pkg/{ => provisioners}/broker/filter.go (100%) rename pkg/{ => provisioners}/broker/filter_test.go (100%) diff --git a/pkg/broker/filter.go b/pkg/provisioners/broker/filter.go similarity index 100% rename from pkg/broker/filter.go rename to pkg/provisioners/broker/filter.go diff --git a/pkg/broker/filter_test.go b/pkg/provisioners/broker/filter_test.go similarity index 100% rename from pkg/broker/filter_test.go rename to pkg/provisioners/broker/filter_test.go From 3f47238e75195d56872ddd61822ac1ea3222758f Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Mon, 11 Feb 2019 11:13:13 -0800 Subject: [PATCH 031/221] Moving cmds to broker --- {cmd => pkg/provisioners}/broker/filter/kodata/HEAD | 0 {cmd => pkg/provisioners}/broker/filter/kodata/LICENSE | 0 {cmd => pkg/provisioners}/broker/filter/kodata/VENDOR-LICENSE | 0 {cmd => pkg/provisioners}/broker/filter/main.go | 2 +- {cmd => pkg/provisioners}/broker/ingress/kodata/HEAD | 0 {cmd => pkg/provisioners}/broker/ingress/kodata/LICENSE | 0 {cmd => pkg/provisioners}/broker/ingress/kodata/VENDOR-LICENSE | 0 {cmd => pkg/provisioners}/broker/ingress/main.go | 0 pkg/provisioners/broker/{filter.go => receiver.go} | 0 pkg/provisioners/broker/{filter_test.go => receiver_test.go} | 0 10 files changed, 1 insertion(+), 1 deletion(-) rename {cmd => pkg/provisioners}/broker/filter/kodata/HEAD (100%) rename {cmd => pkg/provisioners}/broker/filter/kodata/LICENSE (100%) rename {cmd => pkg/provisioners}/broker/filter/kodata/VENDOR-LICENSE (100%) rename {cmd => pkg/provisioners}/broker/filter/main.go (97%) rename {cmd => pkg/provisioners}/broker/ingress/kodata/HEAD (100%) rename {cmd => pkg/provisioners}/broker/ingress/kodata/LICENSE (100%) rename {cmd => pkg/provisioners}/broker/ingress/kodata/VENDOR-LICENSE (100%) rename {cmd => pkg/provisioners}/broker/ingress/main.go (100%) rename pkg/provisioners/broker/{filter.go => receiver.go} (100%) rename pkg/provisioners/broker/{filter_test.go => receiver_test.go} (100%) diff --git a/cmd/broker/filter/kodata/HEAD b/pkg/provisioners/broker/filter/kodata/HEAD similarity index 100% rename from cmd/broker/filter/kodata/HEAD rename to pkg/provisioners/broker/filter/kodata/HEAD diff --git a/cmd/broker/filter/kodata/LICENSE b/pkg/provisioners/broker/filter/kodata/LICENSE similarity index 100% rename from cmd/broker/filter/kodata/LICENSE rename to pkg/provisioners/broker/filter/kodata/LICENSE diff --git a/cmd/broker/filter/kodata/VENDOR-LICENSE b/pkg/provisioners/broker/filter/kodata/VENDOR-LICENSE similarity index 100% rename from cmd/broker/filter/kodata/VENDOR-LICENSE rename to pkg/provisioners/broker/filter/kodata/VENDOR-LICENSE diff --git a/cmd/broker/filter/main.go b/pkg/provisioners/broker/filter/main.go similarity index 97% rename from cmd/broker/filter/main.go rename to pkg/provisioners/broker/filter/main.go index 0c39dec0550..3a394be949e 100644 --- a/cmd/broker/filter/main.go +++ b/pkg/provisioners/broker/filter/main.go @@ -20,8 +20,8 @@ import ( "flag" eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" - "github.com/knative/eventing/pkg/broker" "github.com/knative/eventing/pkg/provisioners" + "github.com/knative/eventing/pkg/provisioners/broker" "github.com/knative/pkg/signals" "go.uber.org/zap" "go.uber.org/zap/zapcore" diff --git a/cmd/broker/ingress/kodata/HEAD b/pkg/provisioners/broker/ingress/kodata/HEAD similarity index 100% rename from cmd/broker/ingress/kodata/HEAD rename to pkg/provisioners/broker/ingress/kodata/HEAD diff --git a/cmd/broker/ingress/kodata/LICENSE b/pkg/provisioners/broker/ingress/kodata/LICENSE similarity index 100% rename from cmd/broker/ingress/kodata/LICENSE rename to pkg/provisioners/broker/ingress/kodata/LICENSE diff --git a/cmd/broker/ingress/kodata/VENDOR-LICENSE b/pkg/provisioners/broker/ingress/kodata/VENDOR-LICENSE similarity index 100% rename from cmd/broker/ingress/kodata/VENDOR-LICENSE rename to pkg/provisioners/broker/ingress/kodata/VENDOR-LICENSE diff --git a/cmd/broker/ingress/main.go b/pkg/provisioners/broker/ingress/main.go similarity index 100% rename from cmd/broker/ingress/main.go rename to pkg/provisioners/broker/ingress/main.go diff --git a/pkg/provisioners/broker/filter.go b/pkg/provisioners/broker/receiver.go similarity index 100% rename from pkg/provisioners/broker/filter.go rename to pkg/provisioners/broker/receiver.go diff --git a/pkg/provisioners/broker/filter_test.go b/pkg/provisioners/broker/receiver_test.go similarity index 100% rename from pkg/provisioners/broker/filter_test.go rename to pkg/provisioners/broker/receiver_test.go From 3070157a8cbba100fd31fa3cbaf9982f67e8c030 Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Mon, 11 Feb 2019 11:48:15 -0800 Subject: [PATCH 032/221] updating controller --- config/500-controller.yaml | 4 ++-- pkg/provisioners/broker/filter/kodata/HEAD | 1 - pkg/provisioners/broker/filter/kodata/LICENSE | 1 - pkg/provisioners/broker/filter/kodata/VENDOR-LICENSE | 1 - pkg/provisioners/broker/ingress/kodata/HEAD | 1 - pkg/provisioners/broker/ingress/kodata/LICENSE | 1 - pkg/provisioners/broker/ingress/kodata/VENDOR-LICENSE | 1 - 7 files changed, 2 insertions(+), 8 deletions(-) delete mode 120000 pkg/provisioners/broker/filter/kodata/HEAD delete mode 120000 pkg/provisioners/broker/filter/kodata/LICENSE delete mode 120000 pkg/provisioners/broker/filter/kodata/VENDOR-LICENSE delete mode 120000 pkg/provisioners/broker/ingress/kodata/HEAD delete mode 120000 pkg/provisioners/broker/ingress/kodata/LICENSE delete mode 120000 pkg/provisioners/broker/ingress/kodata/VENDOR-LICENSE diff --git a/config/500-controller.yaml b/config/500-controller.yaml index 15d76a8cf3a..92ca02e7e19 100644 --- a/config/500-controller.yaml +++ b/config/500-controller.yaml @@ -36,11 +36,11 @@ spec: ] env: - name: INGRESS_IMAGE - value: github.com/knative/eventing/cmd/broker/ingress + value: github.com/knative/eventing/pkg/provisioners/broker/ingress - name: INGRESS_SERVICE_ACCOUNT value: default - name: FILTER_IMAGE - value: github.com/knative/eventing/cmd/broker/filter + value: github.com/knative/eventing/pkg/provisioners/broker/filter - name: FILTER_SERVICE_ACCOUNT value: broker-filter volumeMounts: diff --git a/pkg/provisioners/broker/filter/kodata/HEAD b/pkg/provisioners/broker/filter/kodata/HEAD deleted file mode 120000 index 481bd4eff49..00000000000 --- a/pkg/provisioners/broker/filter/kodata/HEAD +++ /dev/null @@ -1 +0,0 @@ -../../../../.git/HEAD \ No newline at end of file diff --git a/pkg/provisioners/broker/filter/kodata/LICENSE b/pkg/provisioners/broker/filter/kodata/LICENSE deleted file mode 120000 index 14776154326..00000000000 --- a/pkg/provisioners/broker/filter/kodata/LICENSE +++ /dev/null @@ -1 +0,0 @@ -../../../../LICENSE \ No newline at end of file diff --git a/pkg/provisioners/broker/filter/kodata/VENDOR-LICENSE b/pkg/provisioners/broker/filter/kodata/VENDOR-LICENSE deleted file mode 120000 index 7322c09d957..00000000000 --- a/pkg/provisioners/broker/filter/kodata/VENDOR-LICENSE +++ /dev/null @@ -1 +0,0 @@ -../../../../third_party/VENDOR-LICENSE \ No newline at end of file diff --git a/pkg/provisioners/broker/ingress/kodata/HEAD b/pkg/provisioners/broker/ingress/kodata/HEAD deleted file mode 120000 index 481bd4eff49..00000000000 --- a/pkg/provisioners/broker/ingress/kodata/HEAD +++ /dev/null @@ -1 +0,0 @@ -../../../../.git/HEAD \ No newline at end of file diff --git a/pkg/provisioners/broker/ingress/kodata/LICENSE b/pkg/provisioners/broker/ingress/kodata/LICENSE deleted file mode 120000 index 14776154326..00000000000 --- a/pkg/provisioners/broker/ingress/kodata/LICENSE +++ /dev/null @@ -1 +0,0 @@ -../../../../LICENSE \ No newline at end of file diff --git a/pkg/provisioners/broker/ingress/kodata/VENDOR-LICENSE b/pkg/provisioners/broker/ingress/kodata/VENDOR-LICENSE deleted file mode 120000 index 7322c09d957..00000000000 --- a/pkg/provisioners/broker/ingress/kodata/VENDOR-LICENSE +++ /dev/null @@ -1 +0,0 @@ -../../../../third_party/VENDOR-LICENSE \ No newline at end of file From 0957fda7be1696e91311d5b5a29fb010a2fff95b Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Mon, 11 Feb 2019 12:10:50 -0800 Subject: [PATCH 033/221] Moving provider and reconciler to reconciler folder, and merging them into one --- cmd/controller/main.go | 4 +- pkg/provisioners/broker/provider.go | 101 ------------------ pkg/provisioners/trigger/provider.go | 85 --------------- .../v1alpha1/broker/broker.go} | 77 +++++++++++++ .../v1alpha1/trigger/trigger.go} | 63 ++++++++++- 5 files changed, 141 insertions(+), 189 deletions(-) delete mode 100644 pkg/provisioners/broker/provider.go delete mode 100644 pkg/provisioners/trigger/provider.go rename pkg/{provisioners/broker/reconcile.go => reconciler/v1alpha1/broker/broker.go} (82%) rename pkg/{provisioners/trigger/reconcile.go => reconciler/v1alpha1/trigger/trigger.go} (89%) diff --git a/cmd/controller/main.go b/cmd/controller/main.go index 02694da187d..fdc4acc6d69 100644 --- a/cmd/controller/main.go +++ b/cmd/controller/main.go @@ -24,10 +24,10 @@ import ( "os" "time" - "github.com/knative/eventing/pkg/provisioners/broker" "github.com/knative/eventing/pkg/provisioners/namespace" - "github.com/knative/eventing/pkg/provisioners/trigger" + "github.com/knative/eventing/pkg/reconciler/v1alpha1/broker" "github.com/knative/eventing/pkg/reconciler/v1alpha1/subscription" + "github.com/knative/eventing/pkg/reconciler/v1alpha1/trigger" "k8s.io/apimachinery/pkg/runtime" "sigs.k8s.io/controller-runtime/pkg/controller" "sigs.k8s.io/controller-runtime/pkg/manager" diff --git a/pkg/provisioners/broker/provider.go b/pkg/provisioners/broker/provider.go deleted file mode 100644 index 3136269a5df..00000000000 --- a/pkg/provisioners/broker/provider.go +++ /dev/null @@ -1,101 +0,0 @@ -/* -Copyright 2018 The Knative Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT 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 broker - -import ( - "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" - "go.uber.org/zap" - "k8s.io/client-go/dynamic" - "k8s.io/client-go/rest" - "k8s.io/client-go/tools/record" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller" - "sigs.k8s.io/controller-runtime/pkg/handler" - "sigs.k8s.io/controller-runtime/pkg/manager" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - "sigs.k8s.io/controller-runtime/pkg/source" -) - -const ( - // controllerAgentName is the string used by this controller to identify - // itself when creating events. - controllerAgentName = "broker-controller" -) - -type reconciler struct { - client client.Client - restConfig *rest.Config - dynamicClient dynamic.Interface - recorder record.EventRecorder - - logger *zap.Logger - - ingressImage string - ingressServiceAccountName string - filterImage string - filterServiceAccountName string -} - -// Verify the struct implements reconcile.Reconciler -var _ reconcile.Reconciler = &reconciler{} - -// ProvideController returns a function that returns a Broker controller. -func ProvideController(logger *zap.Logger, ingressImage, ingressServiceAccount, filterImage, filterServiceAccount string) func(manager.Manager) (controller.Controller, error) { - return func(mgr manager.Manager) (controller.Controller, error) { - // Setup a new controller to Reconcile Brokers. - c, err := controller.New(controllerAgentName, mgr, controller.Options{ - Reconciler: &reconciler{ - recorder: mgr.GetRecorder(controllerAgentName), - logger: logger, - - ingressImage: ingressImage, - ingressServiceAccountName: ingressServiceAccount, - filterImage: filterImage, - filterServiceAccountName: filterServiceAccount, - }, - }) - if err != nil { - return nil, err - } - - // Watch Subscription events and enqueue Subscription object key. - if err = c.Watch(&source.Kind{Type: &v1alpha1.Broker{}}, &handler.EnqueueRequestForObject{}); err != nil { - return nil, err - } - - err = c.Watch(&source.Kind{ - Type: &v1alpha1.Channel{}, - }, &handler.EnqueueRequestForOwner{OwnerType: &v1alpha1.Broker{}, IsController: true}) - if err != nil { - return nil, err - } - - return c, nil - } -} - -func (r *reconciler) InjectClient(c client.Client) error { - r.client = c - return nil -} - -func (r *reconciler) InjectConfig(c *rest.Config) error { - r.restConfig = c - var err error - r.dynamicClient, err = dynamic.NewForConfig(c) - return err -} diff --git a/pkg/provisioners/trigger/provider.go b/pkg/provisioners/trigger/provider.go deleted file mode 100644 index 1bd62841435..00000000000 --- a/pkg/provisioners/trigger/provider.go +++ /dev/null @@ -1,85 +0,0 @@ -/* -Copyright 2018 The Knative Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT 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 trigger - -import ( - "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" - "go.uber.org/zap" - "k8s.io/client-go/dynamic" - "k8s.io/client-go/rest" - "k8s.io/client-go/tools/record" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller" - "sigs.k8s.io/controller-runtime/pkg/handler" - "sigs.k8s.io/controller-runtime/pkg/manager" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - "sigs.k8s.io/controller-runtime/pkg/source" -) - -const ( - // controllerAgentName is the string used by this controller to identify - // itself when creating events. - controllerAgentName = "trigger-controller" -) - -type reconciler struct { - client client.Client - restConfig *rest.Config - dynamicClient dynamic.Interface - recorder record.EventRecorder - - logger *zap.Logger -} - -// Verify the struct implements reconcile.Reconciler -var _ reconcile.Reconciler = &reconciler{} - -// ProvideController returns a function that returns a Broker controller. -func ProvideController(logger *zap.Logger) func(manager.Manager) (controller.Controller, error) { - return func(mgr manager.Manager) (controller.Controller, error) { - // Setup a new controller to Reconcile Brokers. - r := &reconciler{ - recorder: mgr.GetRecorder(controllerAgentName), - logger: logger, - } - c, err := controller.New(controllerAgentName, mgr, controller.Options{ - Reconciler: r, - }) - if err != nil { - return nil, err - } - - // Watch Subscription events and enqueue Subscription object key. - if err = c.Watch(&source.Kind{Type: &v1alpha1.Trigger{}}, &handler.EnqueueRequestForObject{}); err != nil { - return nil, err - } - - return c, nil - } -} - -func (r *reconciler) InjectClient(c client.Client) error { - r.client = c - return nil -} - -func (r *reconciler) InjectConfig(c *rest.Config) error { - r.restConfig = c - var err error - r.dynamicClient, err = dynamic.NewForConfig(c) - return err -} diff --git a/pkg/provisioners/broker/reconcile.go b/pkg/reconciler/v1alpha1/broker/broker.go similarity index 82% rename from pkg/provisioners/broker/reconcile.go rename to pkg/reconciler/v1alpha1/broker/broker.go index 7abd4cf8d6e..ff9f03c13f3 100644 --- a/pkg/provisioners/broker/reconcile.go +++ b/pkg/reconciler/v1alpha1/broker/broker.go @@ -20,6 +20,14 @@ import ( "context" "fmt" + "k8s.io/client-go/dynamic" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/record" + "sigs.k8s.io/controller-runtime/pkg/controller" + "sigs.k8s.io/controller-runtime/pkg/handler" + "sigs.k8s.io/controller-runtime/pkg/manager" + "sigs.k8s.io/controller-runtime/pkg/source" + "github.com/knative/eventing/pkg/reconciler/names" "github.com/knative/eventing/contrib/gcppubsub/pkg/util/logging" @@ -41,15 +49,84 @@ import ( "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" runtimeclient "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/reconcile" ) const ( + // controllerAgentName is the string used by this controller to identify + // itself when creating events. + controllerAgentName = "broker-controller" + // Name of the corev1.Events emitted from the reconciliation process brokerReconciled = "BrokerReconciled" brokerUpdateStatusFailed = "BrokerUpdateStatusFailed" ) +type reconciler struct { + client client.Client + restConfig *rest.Config + dynamicClient dynamic.Interface + recorder record.EventRecorder + + logger *zap.Logger + + ingressImage string + ingressServiceAccountName string + filterImage string + filterServiceAccountName string +} + +// Verify the struct implements reconcile.Reconciler +var _ reconcile.Reconciler = &reconciler{} + +// ProvideController returns a function that returns a Broker controller. +func ProvideController(logger *zap.Logger, ingressImage, ingressServiceAccount, filterImage, filterServiceAccount string) func(manager.Manager) (controller.Controller, error) { + return func(mgr manager.Manager) (controller.Controller, error) { + // Setup a new controller to Reconcile Brokers. + c, err := controller.New(controllerAgentName, mgr, controller.Options{ + Reconciler: &reconciler{ + recorder: mgr.GetRecorder(controllerAgentName), + logger: logger, + + ingressImage: ingressImage, + ingressServiceAccountName: ingressServiceAccount, + filterImage: filterImage, + filterServiceAccountName: filterServiceAccount, + }, + }) + if err != nil { + return nil, err + } + + // Watch Subscription events and enqueue Subscription object key. + if err = c.Watch(&source.Kind{Type: &v1alpha1.Broker{}}, &handler.EnqueueRequestForObject{}); err != nil { + return nil, err + } + + err = c.Watch(&source.Kind{ + Type: &v1alpha1.Channel{}, + }, &handler.EnqueueRequestForOwner{OwnerType: &v1alpha1.Broker{}, IsController: true}) + if err != nil { + return nil, err + } + + return c, nil + } +} + +func (r *reconciler) InjectClient(c client.Client) error { + r.client = c + return nil +} + +func (r *reconciler) InjectConfig(c *rest.Config) error { + r.restConfig = c + var err error + r.dynamicClient, err = dynamic.NewForConfig(c) + return err +} + // Reconcile compares the actual state with the desired, and attempts to // converge the two. It then updates the Status block of the Broker resource // with the current status of the resource. diff --git a/pkg/provisioners/trigger/reconcile.go b/pkg/reconciler/v1alpha1/trigger/trigger.go similarity index 89% rename from pkg/provisioners/trigger/reconcile.go rename to pkg/reconciler/v1alpha1/trigger/trigger.go index 668742d1308..d7ce3cf2c37 100644 --- a/pkg/provisioners/trigger/reconcile.go +++ b/pkg/reconciler/v1alpha1/trigger/trigger.go @@ -20,11 +20,19 @@ import ( "context" "fmt" + "k8s.io/client-go/dynamic" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/record" + "sigs.k8s.io/controller-runtime/pkg/controller" + "sigs.k8s.io/controller-runtime/pkg/handler" + "sigs.k8s.io/controller-runtime/pkg/manager" + "sigs.k8s.io/controller-runtime/pkg/source" + "github.com/knative/eventing/pkg/reconciler/names" "github.com/knative/eventing/contrib/gcppubsub/pkg/util/logging" "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" - "github.com/knative/eventing/pkg/provisioners/broker" + "github.com/knative/eventing/pkg/reconciler/v1alpha1/broker" "github.com/knative/eventing/pkg/reconciler/v1alpha1/subscription" istiov1alpha3 "github.com/knative/pkg/apis/istio/v1alpha3" "go.uber.org/zap" @@ -38,15 +46,68 @@ import ( "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" runtimeclient "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/reconcile" ) const ( + // controllerAgentName is the string used by this controller to identify + // itself when creating events. + controllerAgentName = "trigger-controller" + // Name of the corev1.Events emitted from the reconciliation process triggerReconciled = "TriggerReconciled" triggerUpdateStatusFailed = "TriggerUpdateStatusFailed" ) +type reconciler struct { + client client.Client + restConfig *rest.Config + dynamicClient dynamic.Interface + recorder record.EventRecorder + + logger *zap.Logger +} + +// Verify the struct implements reconcile.Reconciler +var _ reconcile.Reconciler = &reconciler{} + +// ProvideController returns a function that returns a Broker controller. +func ProvideController(logger *zap.Logger) func(manager.Manager) (controller.Controller, error) { + return func(mgr manager.Manager) (controller.Controller, error) { + // Setup a new controller to Reconcile Brokers. + r := &reconciler{ + recorder: mgr.GetRecorder(controllerAgentName), + logger: logger, + } + c, err := controller.New(controllerAgentName, mgr, controller.Options{ + Reconciler: r, + }) + if err != nil { + return nil, err + } + + // Watch Subscription events and enqueue Subscription object key. + if err = c.Watch(&source.Kind{Type: &v1alpha1.Trigger{}}, &handler.EnqueueRequestForObject{}); err != nil { + return nil, err + } + + return c, nil + } +} + +func (r *reconciler) InjectClient(c client.Client) error { + r.client = c + return nil +} + +func (r *reconciler) InjectConfig(c *rest.Config) error { + r.restConfig = c + var err error + r.dynamicClient, err = dynamic.NewForConfig(c) + return err +} + // Reconcile compares the actual state with the desired, and attempts to // converge the two. It then updates the Status block of the Trigger resource // with the current status of the resource. From 509c8a1741ae03f21324906b2d9160adece17095 Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Mon, 11 Feb 2019 16:10:40 -0800 Subject: [PATCH 034/221] Adding verbs to dispatcher --- contrib/gcppubsub/config/gcppubsub.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/contrib/gcppubsub/config/gcppubsub.yaml b/contrib/gcppubsub/config/gcppubsub.yaml index 02359d6d10c..7e373b50280 100644 --- a/contrib/gcppubsub/config/gcppubsub.yaml +++ b/contrib/gcppubsub/config/gcppubsub.yaml @@ -161,6 +161,14 @@ rules: - get - list - watch + - apiGroups: + - "" # Core API Group. + resources: + - events + verbs: + - create + - patch + - update --- From d33308b1077b2a46832618d5f6263a422318a7de Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Mon, 11 Feb 2019 16:51:18 -0800 Subject: [PATCH 035/221] Moving back mains to cmd --- cmd/broker/filter/kodata/HEAD | 1 + cmd/broker/filter/kodata/LICENSE | 1 + cmd/broker/filter/kodata/VENDOR-LICENSE | 1 + {pkg/provisioners => cmd}/broker/filter/main.go | 0 cmd/broker/ingress/kodata/HEAD | 1 + cmd/broker/ingress/kodata/LICENSE | 1 + cmd/broker/ingress/kodata/VENDOR-LICENSE | 1 + {pkg/provisioners => cmd}/broker/ingress/main.go | 0 8 files changed, 6 insertions(+) create mode 120000 cmd/broker/filter/kodata/HEAD create mode 120000 cmd/broker/filter/kodata/LICENSE create mode 120000 cmd/broker/filter/kodata/VENDOR-LICENSE rename {pkg/provisioners => cmd}/broker/filter/main.go (100%) create mode 120000 cmd/broker/ingress/kodata/HEAD create mode 120000 cmd/broker/ingress/kodata/LICENSE create mode 120000 cmd/broker/ingress/kodata/VENDOR-LICENSE rename {pkg/provisioners => cmd}/broker/ingress/main.go (100%) diff --git a/cmd/broker/filter/kodata/HEAD b/cmd/broker/filter/kodata/HEAD new file mode 120000 index 00000000000..481bd4eff49 --- /dev/null +++ b/cmd/broker/filter/kodata/HEAD @@ -0,0 +1 @@ +../../../../.git/HEAD \ No newline at end of file diff --git a/cmd/broker/filter/kodata/LICENSE b/cmd/broker/filter/kodata/LICENSE new file mode 120000 index 00000000000..14776154326 --- /dev/null +++ b/cmd/broker/filter/kodata/LICENSE @@ -0,0 +1 @@ +../../../../LICENSE \ No newline at end of file diff --git a/cmd/broker/filter/kodata/VENDOR-LICENSE b/cmd/broker/filter/kodata/VENDOR-LICENSE new file mode 120000 index 00000000000..7322c09d957 --- /dev/null +++ b/cmd/broker/filter/kodata/VENDOR-LICENSE @@ -0,0 +1 @@ +../../../../third_party/VENDOR-LICENSE \ No newline at end of file diff --git a/pkg/provisioners/broker/filter/main.go b/cmd/broker/filter/main.go similarity index 100% rename from pkg/provisioners/broker/filter/main.go rename to cmd/broker/filter/main.go diff --git a/cmd/broker/ingress/kodata/HEAD b/cmd/broker/ingress/kodata/HEAD new file mode 120000 index 00000000000..481bd4eff49 --- /dev/null +++ b/cmd/broker/ingress/kodata/HEAD @@ -0,0 +1 @@ +../../../../.git/HEAD \ No newline at end of file diff --git a/cmd/broker/ingress/kodata/LICENSE b/cmd/broker/ingress/kodata/LICENSE new file mode 120000 index 00000000000..14776154326 --- /dev/null +++ b/cmd/broker/ingress/kodata/LICENSE @@ -0,0 +1 @@ +../../../../LICENSE \ No newline at end of file diff --git a/cmd/broker/ingress/kodata/VENDOR-LICENSE b/cmd/broker/ingress/kodata/VENDOR-LICENSE new file mode 120000 index 00000000000..7322c09d957 --- /dev/null +++ b/cmd/broker/ingress/kodata/VENDOR-LICENSE @@ -0,0 +1 @@ +../../../../third_party/VENDOR-LICENSE \ No newline at end of file diff --git a/pkg/provisioners/broker/ingress/main.go b/cmd/broker/ingress/main.go similarity index 100% rename from pkg/provisioners/broker/ingress/main.go rename to cmd/broker/ingress/main.go From af83baa8822c8de06445604a7763d688afe69a17 Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Mon, 11 Feb 2019 16:52:26 -0800 Subject: [PATCH 036/221] Updating config --- config/500-controller.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/500-controller.yaml b/config/500-controller.yaml index 92ca02e7e19..15d76a8cf3a 100644 --- a/config/500-controller.yaml +++ b/config/500-controller.yaml @@ -36,11 +36,11 @@ spec: ] env: - name: INGRESS_IMAGE - value: github.com/knative/eventing/pkg/provisioners/broker/ingress + value: github.com/knative/eventing/cmd/broker/ingress - name: INGRESS_SERVICE_ACCOUNT value: default - name: FILTER_IMAGE - value: github.com/knative/eventing/pkg/provisioners/broker/filter + value: github.com/knative/eventing/cmd/broker/filter - name: FILTER_SERVICE_ACCOUNT value: broker-filter volumeMounts: From 8df699cdc1fe199ee61b3f96f764594326b62a3c Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Mon, 11 Feb 2019 17:10:40 -0800 Subject: [PATCH 037/221] Moving resources to reconcilers --- pkg/reconciler/v1alpha1/broker/broker.go | 2 +- .../v1alpha1}/broker/resources/filter.go | 0 .../v1alpha1}/broker/resources/ingress.go | 0 3 files changed, 1 insertion(+), 1 deletion(-) rename pkg/{provisioners => reconciler/v1alpha1}/broker/resources/filter.go (100%) rename pkg/{provisioners => reconciler/v1alpha1}/broker/resources/ingress.go (100%) diff --git a/pkg/reconciler/v1alpha1/broker/broker.go b/pkg/reconciler/v1alpha1/broker/broker.go index ff9f03c13f3..21961fb06f3 100644 --- a/pkg/reconciler/v1alpha1/broker/broker.go +++ b/pkg/reconciler/v1alpha1/broker/broker.go @@ -36,7 +36,7 @@ import ( "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime/schema" - "github.com/knative/eventing/pkg/provisioners/broker/resources" + "github.com/knative/eventing/pkg/reconciler/v1alpha1/broker/resources" "go.uber.org/zap" diff --git a/pkg/provisioners/broker/resources/filter.go b/pkg/reconciler/v1alpha1/broker/resources/filter.go similarity index 100% rename from pkg/provisioners/broker/resources/filter.go rename to pkg/reconciler/v1alpha1/broker/resources/filter.go diff --git a/pkg/provisioners/broker/resources/ingress.go b/pkg/reconciler/v1alpha1/broker/resources/ingress.go similarity index 100% rename from pkg/provisioners/broker/resources/ingress.go rename to pkg/reconciler/v1alpha1/broker/resources/ingress.go From bd6a8fa9c62460ee696854fb44a898e72e249ae2 Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Mon, 11 Feb 2019 17:16:45 -0800 Subject: [PATCH 038/221] Moving broker folder back where it belongs --- cmd/broker/filter/main.go | 2 +- pkg/{provisioners => }/broker/receiver.go | 0 pkg/{provisioners => }/broker/receiver_test.go | 0 3 files changed, 1 insertion(+), 1 deletion(-) rename pkg/{provisioners => }/broker/receiver.go (100%) rename pkg/{provisioners => }/broker/receiver_test.go (100%) diff --git a/cmd/broker/filter/main.go b/cmd/broker/filter/main.go index 3a394be949e..0c39dec0550 100644 --- a/cmd/broker/filter/main.go +++ b/cmd/broker/filter/main.go @@ -20,8 +20,8 @@ import ( "flag" eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" + "github.com/knative/eventing/pkg/broker" "github.com/knative/eventing/pkg/provisioners" - "github.com/knative/eventing/pkg/provisioners/broker" "github.com/knative/pkg/signals" "go.uber.org/zap" "go.uber.org/zap/zapcore" diff --git a/pkg/provisioners/broker/receiver.go b/pkg/broker/receiver.go similarity index 100% rename from pkg/provisioners/broker/receiver.go rename to pkg/broker/receiver.go diff --git a/pkg/provisioners/broker/receiver_test.go b/pkg/broker/receiver_test.go similarity index 100% rename from pkg/provisioners/broker/receiver_test.go rename to pkg/broker/receiver_test.go From 3b84c915e20e6dd600537f38b916e715688fed81 Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Tue, 12 Feb 2019 09:16:37 -0800 Subject: [PATCH 039/221] Revert "Merge branch 'broker-new-model' into broker-new" This reverts commit d567412b062233463335c7feea94be795f7f2e15, reversing changes made to bd6a8fa9c62460ee696854fb44a898e72e249ae2. --- .../eventing/v1alpha1/trigger_defaults.go | 5 ++- pkg/apis/eventing/v1alpha1/trigger_types.go | 11 ++----- .../eventing/v1alpha1/trigger_validation.go | 4 +-- .../v1alpha1/zz_generated.deepcopy.go | 32 ------------------- pkg/broker/receiver.go | 17 +++++----- t2.yaml | 6 ++-- 6 files changed, 18 insertions(+), 57 deletions(-) diff --git a/pkg/apis/eventing/v1alpha1/trigger_defaults.go b/pkg/apis/eventing/v1alpha1/trigger_defaults.go index 1869815a849..fd785c8bf38 100644 --- a/pkg/apis/eventing/v1alpha1/trigger_defaults.go +++ b/pkg/apis/eventing/v1alpha1/trigger_defaults.go @@ -24,8 +24,7 @@ func (ts *TriggerSpec) SetDefaults() { if ts.Broker == "" { ts.Broker = "default" } - // Make empty filter selector so that we allow everything. - if ts.Filter == nil { - ts.Filter = &FilterSelector{map[string]string{}} + if ts.Type == "" { + ts.Type = "Any" } } diff --git a/pkg/apis/eventing/v1alpha1/trigger_types.go b/pkg/apis/eventing/v1alpha1/trigger_types.go index 39e199ea6cf..86b7c121bf6 100644 --- a/pkg/apis/eventing/v1alpha1/trigger_types.go +++ b/pkg/apis/eventing/v1alpha1/trigger_types.go @@ -58,16 +58,11 @@ type TriggerSpec struct { // +optional DeprecatedGeneration int64 `json:"generation,omitempty"` - Broker string `json:"broker,omitempty"` - - // +optional - Filter *FilterSelector `json:"filter,omitempty"` - + Broker string `json:"broker,omitempty"` Subscriber *SubscriberSpec `json:"subscriber,omitempty"` -} -type FilterSelector struct { - Headers map[string]string `json:"headers,omitempty" protobuf:"bytes,1,rep,name=headers"` + Type string `json:"type,omitempty"` + Source string `json:"source,omitempty"` } var triggerCondSet = duckv1alpha1.NewLivingConditionSet(TriggerConditionBrokerExists, TriggerConditionKubernetesService, TriggerConditionVirtualService, TriggerConditionSubscribed) diff --git a/pkg/apis/eventing/v1alpha1/trigger_validation.go b/pkg/apis/eventing/v1alpha1/trigger_validation.go index 42057cf9bef..9d0178a464f 100644 --- a/pkg/apis/eventing/v1alpha1/trigger_validation.go +++ b/pkg/apis/eventing/v1alpha1/trigger_validation.go @@ -32,8 +32,8 @@ func (ts *TriggerSpec) Validate() *apis.FieldError { errs = errs.Also(fe) } - if ts.Filter == nil { - fe := apis.ErrMissingField("filters") + if ts.Type == "" { + fe := apis.ErrMissingField("type") errs = errs.Also(fe) } diff --git a/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go index 167f6d00748..fc8f77d0aee 100644 --- a/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go @@ -374,29 +374,6 @@ func (in *ClusterChannelProvisionerStatus) DeepCopy() *ClusterChannelProvisioner return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FilterSelector) DeepCopyInto(out *FilterSelector) { - *out = *in - if in.Headers != nil { - in, out := &in.Headers, &out.Headers - *out = make(map[string]string, len(*in)) - for key, val := range *in { - (*out)[key] = val - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FilterSelector. -func (in *FilterSelector) DeepCopy() *FilterSelector { - if in == nil { - return nil - } - out := new(FilterSelector) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ReplyStrategy) DeepCopyInto(out *ReplyStrategy) { *out = *in @@ -656,15 +633,6 @@ func (in *TriggerList) DeepCopyObject() runtime.Object { // 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 - if *in == nil { - *out = nil - } else { - *out = new(FilterSelector) - (*in).DeepCopyInto(*out) - } - } if in.Subscriber != nil { in, out := &in.Subscriber, &out.Subscriber if *in == nil { diff --git a/pkg/broker/receiver.go b/pkg/broker/receiver.go index 78002d23b36..60e2ae3d6ac 100644 --- a/pkg/broker/receiver.go +++ b/pkg/broker/receiver.go @@ -23,7 +23,6 @@ import ( eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" "github.com/knative/eventing/pkg/provisioners" "go.uber.org/zap" - "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/manager" @@ -99,12 +98,14 @@ func (r *Receiver) getTrigger(ctx context.Context, ref provisioners.ChannelRefer } func (r *Receiver) shouldSendMessage(t *eventingv1alpha1.TriggerSpec, m *provisioners.Message) bool { - // This conversion to selector should be done only once, possibly upon creation of the trigger - // in case the filters are immutable. All validations should be performed then. - selector := labels.SelectorFromValidatedSet(labels.Set(t.Filter.Headers)) - matched := selector.Matches(labels.Set(m.Headers)) - if !matched { - r.logger.Debug("Selector did not match message headers", zap.String("selector", selector.String()), zap.Any("headers", m.Headers)) + // TODO More filtering! + if t.Type != Any && t.Type != m.Headers["Ce-Eventtype"] { + r.logger.Debug("Wrong type", zap.String("trigger.spec.type", t.Type), zap.String("message.type", m.Headers["Ce-Eventtype"]), zap.Any("m", m)) + return false } - return matched + if t.Source != "" && t.Source != m.Headers["Ce-Source"] { + r.logger.Debug("Wrong source", zap.String("trigger.spec.source", t.Source), zap.String("message.source", m.Headers["Ce-Source"])) + return false + } + return true } diff --git a/t2.yaml b/t2.yaml index 02b2f7ba64d..0e217789a03 100644 --- a/t2.yaml +++ b/t2.yaml @@ -5,12 +5,10 @@ metadata: spec: # Our Cloud Event parsing library seems to have a bug and forces to put type and source in double # quotes (as it thinks the actual value is `"foo"`, not `foo`). - filter: - headers: - Ce-Eventtype: '"com.example.someevent"' - Ce-Source: '"/mycontext/subcontext"' + type: '"com.example.someevent"' subscriber: ref: apiVersion: serving.knative.dev/v1alpha1 kind: Service name: message-dumper + From 2df6bdc6502aedf2310afc73e15f94e713ef2c8a Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Tue, 12 Feb 2019 09:56:26 -0800 Subject: [PATCH 040/221] Updating headers and headerExpressions to attributes and attributeExpressions --- pkg/apis/eventing/v1alpha1/trigger_types.go | 5 +++-- pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go | 8 ++++---- pkg/broker/receiver.go | 12 ++++++------ t.yaml | 2 +- t2.yaml | 2 +- t3.yaml | 4 ++-- 6 files changed, 17 insertions(+), 16 deletions(-) diff --git a/pkg/apis/eventing/v1alpha1/trigger_types.go b/pkg/apis/eventing/v1alpha1/trigger_types.go index 11b86e52b23..75131366d6d 100644 --- a/pkg/apis/eventing/v1alpha1/trigger_types.go +++ b/pkg/apis/eventing/v1alpha1/trigger_types.go @@ -67,8 +67,9 @@ type TriggerSpec struct { } type FilterSelector struct { - Headers map[string]string `json:"headers,omitempty" protobuf:"bytes,1,rep,name=headers"` - HeaderExpressions []metav1.LabelSelectorRequirement `json:"headerExpressions,omitempty" protobuf:"bytes,2,rep,name=headerExpressions"` + Attributes map[string]string `json:"attributes,omitempty" protobuf:"bytes,1,rep,name=attributes"` + // TODO create our own FilterSelectorRequirement + AttributeExpressions []metav1.LabelSelectorRequirement `json:"attributeExpressions,omitempty" protobuf:"bytes,2,rep,name=attributeExpressions"` } var triggerCondSet = duckv1alpha1.NewLivingConditionSet(TriggerConditionBrokerExists, TriggerConditionKubernetesService, TriggerConditionVirtualService, TriggerConditionSubscribed) diff --git a/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go index 2e9b4cc6e90..1672ffe6dc9 100644 --- a/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go @@ -378,15 +378,15 @@ func (in *ClusterChannelProvisionerStatus) DeepCopy() *ClusterChannelProvisioner // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *FilterSelector) DeepCopyInto(out *FilterSelector) { *out = *in - if in.Headers != nil { - in, out := &in.Headers, &out.Headers + if in.Attributes != nil { + in, out := &in.Attributes, &out.Attributes *out = make(map[string]string, len(*in)) for key, val := range *in { (*out)[key] = val } } - if in.HeaderExpressions != nil { - in, out := &in.HeaderExpressions, &out.HeaderExpressions + if in.AttributeExpressions != nil { + in, out := &in.AttributeExpressions, &out.AttributeExpressions *out = make([]meta_v1.LabelSelectorRequirement, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) diff --git a/pkg/broker/receiver.go b/pkg/broker/receiver.go index eaeb633525f..ea009b05f6b 100644 --- a/pkg/broker/receiver.go +++ b/pkg/broker/receiver.go @@ -35,7 +35,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/manager" ) -// Receiver parses Cloud Events and sends them to GCP PubSub. +// Receiver parses Cloud Events and sends them to the channel. type Receiver struct { logger *zap.Logger client client.Client @@ -55,11 +55,11 @@ func New(logger *zap.Logger, client client.Client) (*Receiver, manager.Runnable) } func (r *Receiver) newMessageReceiver() *provisioners.MessageReceiver { - return provisioners.NewMessageReceiver(r.sendEventToTopic, r.logger.Sugar()) + return provisioners.NewMessageReceiver(r.sendEvent, r.logger.Sugar()) } -// sendEventToTopic sends a message to the Cloud Pub/Sub Topic backing the Channel. -func (r *Receiver) sendEventToTopic(channel provisioners.ChannelReference, message *provisioners.Message) error { +// sendEvent sends a message to the Channel. +func (r *Receiver) sendEvent(channel provisioners.ChannelReference, message *provisioners.Message) error { r.logger.Debug("received message") ctx := context.Background() @@ -118,8 +118,8 @@ func (r *Receiver) shouldSendMessage(t *eventingv1alpha1.TriggerSpec, m *provisi func (r *Receiver) buildSelector(ts *eventingv1alpha1.TriggerSpec) (labels.Selector, error) { // Avoid validation of keys and values, otherwise we cannot use LabelSelectors. // Eventually, we will need to create our own Selector implementation with our own Requirement struct. - selector := labels.SelectorFromValidatedSet(labels.Set(ts.Filter.Headers)) - for _, expr := range ts.Filter.HeaderExpressions { + selector := labels.SelectorFromValidatedSet(labels.Set(ts.Filter.Attributes)) + for _, expr := range ts.Filter.AttributeExpressions { var op selection.Operator switch expr.Operator { case v1.LabelSelectorOpIn: diff --git a/t.yaml b/t.yaml index a53dcc1db33..d9427cc9552 100644 --- a/t.yaml +++ b/t.yaml @@ -3,7 +3,7 @@ kind: Trigger metadata: name: t spec: - type: Any + filter: {} subscriber: ref: apiVersion: serving.knative.dev/v1alpha1 diff --git a/t2.yaml b/t2.yaml index 02b2f7ba64d..c95018d4bfb 100644 --- a/t2.yaml +++ b/t2.yaml @@ -6,7 +6,7 @@ spec: # Our Cloud Event parsing library seems to have a bug and forces to put type and source in double # quotes (as it thinks the actual value is `"foo"`, not `foo`). filter: - headers: + attributes: Ce-Eventtype: '"com.example.someevent"' Ce-Source: '"/mycontext/subcontext"' subscriber: diff --git a/t3.yaml b/t3.yaml index 0ed3e969020..1a90d86926b 100644 --- a/t3.yaml +++ b/t3.yaml @@ -6,9 +6,9 @@ spec: # Our Cloud Event parsing library seems to have a bug and forces to put type and source in double # quotes (as it thinks the actual value is `"foo"`, not `foo`). filter: - headers: + attributes: Ce-Source: '"/mycontext/subcontext"' - headerExpressions: + attributeExpressions: - {key: Ce-Eventtype, operator: In, values: ['"com.example.someevent"', '"com.example.someevent1"']} subscriber: ref: From 22efbe0220b4fcced4e263e1d8e602c18c62b71f Mon Sep 17 00:00:00 2001 From: Adam Harwayne Date: Tue, 12 Feb 2019 16:05:36 -0800 Subject: [PATCH 041/221] Reconcilers notice when mroe things change. --- cmd/controller/main.go | 2 +- pkg/provisioners/namespace/provider.go | 106 ------------------ pkg/reconciler/v1alpha1/broker/broker.go | 19 ++-- .../v1alpha1/broker/resources/filter.go | 4 +- .../v1alpha1/namespace/namespace.go} | 94 +++++++++++++++- pkg/reconciler/v1alpha1/trigger/trigger.go | 15 ++- 6 files changed, 117 insertions(+), 123 deletions(-) delete mode 100644 pkg/provisioners/namespace/provider.go rename pkg/{provisioners/namespace/reconcile.go => reconciler/v1alpha1/namespace/namespace.go} (60%) diff --git a/cmd/controller/main.go b/cmd/controller/main.go index 33319ad6169..c4975b4314e 100644 --- a/cmd/controller/main.go +++ b/cmd/controller/main.go @@ -24,7 +24,7 @@ import ( "os" "time" - "github.com/knative/eventing/pkg/provisioners/namespace" + "github.com/knative/eventing/pkg/reconciler/v1alpha1/namespace" "github.com/knative/eventing/pkg/reconciler/v1alpha1/broker" "github.com/knative/eventing/pkg/reconciler/v1alpha1/subscription" "github.com/knative/eventing/pkg/reconciler/v1alpha1/trigger" diff --git a/pkg/provisioners/namespace/provider.go b/pkg/provisioners/namespace/provider.go deleted file mode 100644 index 2107c50fb5d..00000000000 --- a/pkg/provisioners/namespace/provider.go +++ /dev/null @@ -1,106 +0,0 @@ -/* -Copyright 2018 The Knative Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT 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 namespace - -import ( - "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" - "go.uber.org/zap" - v1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/dynamic" - "k8s.io/client-go/rest" - "k8s.io/client-go/tools/record" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller" - "sigs.k8s.io/controller-runtime/pkg/handler" - "sigs.k8s.io/controller-runtime/pkg/manager" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - "sigs.k8s.io/controller-runtime/pkg/source" -) - -const ( - // controllerAgentName is the string used by this controller to identify - // itself when creating events. - controllerAgentName = "knative-eventing-namespace-controller" -) - -type reconciler struct { - client client.Client - restConfig *rest.Config - dynamicClient dynamic.Interface - recorder record.EventRecorder - - logger *zap.Logger -} - -// Verify the struct implements reconcile.Reconciler -var _ reconcile.Reconciler = &reconciler{} - -// ProvideController returns a function that returns a Broker controller. -func ProvideController(logger *zap.Logger) func(manager.Manager) (controller.Controller, error) { - return func(mgr manager.Manager) (controller.Controller, error) { - // Setup a new controller to Reconcile Brokers. - r := &reconciler{ - recorder: mgr.GetRecorder(controllerAgentName), - logger: logger, - } - c, err := controller.New(controllerAgentName, mgr, controller.Options{ - Reconciler: r, - }) - if err != nil { - return nil, err - } - - // Watch Subscription events and enqueue Subscription object key. - if err = c.Watch(&source.Kind{Type: &v1.Namespace{}}, &handler.EnqueueRequestForObject{}); err != nil { - return nil, err - } - - if err = c.Watch(&source.Kind{Type: &v1alpha1.Broker{}}, &handler.EnqueueRequestsFromMapFunc{ToRequests: &namespaceMapper{}}); err != nil { - return nil, err - } - - return c, nil - } -} - -type namespaceMapper struct{} - -var _ handler.Mapper = &namespaceMapper{} - -func (namespaceMapper) Map(o handler.MapObject) []reconcile.Request { - return []reconcile.Request{ - { - NamespacedName: types.NamespacedName{ - Namespace: "", - Name: o.Meta.GetNamespace(), - }, - }, - } -} - -func (r *reconciler) InjectClient(c client.Client) error { - r.client = c - return nil -} - -func (r *reconciler) InjectConfig(c *rest.Config) error { - r.restConfig = c - var err error - r.dynamicClient, err = dynamic.NewForConfig(c) - return err -} diff --git a/pkg/reconciler/v1alpha1/broker/broker.go b/pkg/reconciler/v1alpha1/broker/broker.go index 21961fb06f3..8a79adfd902 100644 --- a/pkg/reconciler/v1alpha1/broker/broker.go +++ b/pkg/reconciler/v1alpha1/broker/broker.go @@ -19,6 +19,7 @@ package broker import ( "context" "fmt" + "k8s.io/apimachinery/pkg/runtime" "k8s.io/client-go/dynamic" "k8s.io/client-go/rest" @@ -99,16 +100,17 @@ func ProvideController(logger *zap.Logger, ingressImage, ingressServiceAccount, return nil, err } - // Watch Subscription events and enqueue Subscription object key. + // Watch Brokers. if err = c.Watch(&source.Kind{Type: &v1alpha1.Broker{}}, &handler.EnqueueRequestForObject{}); err != nil { return nil, err } - err = c.Watch(&source.Kind{ - Type: &v1alpha1.Channel{}, - }, &handler.EnqueueRequestForOwner{OwnerType: &v1alpha1.Broker{}, IsController: true}) - if err != nil { - return nil, err + // Watch all the resources that the Broker reconciles. + for _, t := range []runtime.Object{ &v1alpha1.Channel{}, &corev1.Service{}, &v1.Deployment{} } { + err = c.Watch(&source.Kind{Type: t}, &handler.EnqueueRequestForOwner{OwnerType: &v1alpha1.Broker{}, IsController: true}) + if err != nil { + return nil, err + } } return c, nil @@ -261,14 +263,11 @@ func (r *reconciler) updateStatus(broker *v1alpha1.Broker) (*v1alpha1.Broker, er } func (r *reconciler) reconcileFilterDeployment(ctx context.Context, b *v1alpha1.Broker) (*v1.Deployment, error) { - expected, err := resources.MakeFilterDeployment(&resources.FilterArgs{ + expected := resources.MakeFilterDeployment(&resources.FilterArgs{ Broker: b, Image: r.filterImage, ServiceAccountName: r.filterServiceAccountName, }) - if err != nil { - return nil, err - } return r.reconcileDeployment(ctx, expected) } diff --git a/pkg/reconciler/v1alpha1/broker/resources/filter.go b/pkg/reconciler/v1alpha1/broker/resources/filter.go index 4de9be6d0df..38d049f068e 100644 --- a/pkg/reconciler/v1alpha1/broker/resources/filter.go +++ b/pkg/reconciler/v1alpha1/broker/resources/filter.go @@ -34,7 +34,7 @@ type FilterArgs struct { ServiceAccountName string } -func MakeFilterDeployment(args *FilterArgs) (*appsv1.Deployment, error) { +func MakeFilterDeployment(args *FilterArgs) *appsv1.Deployment { return &appsv1.Deployment{ ObjectMeta: metav1.ObjectMeta{ Namespace: args.Broker.Namespace, @@ -75,7 +75,7 @@ func MakeFilterDeployment(args *FilterArgs) (*appsv1.Deployment, error) { }, }, }, - }, nil + } } func MakeFilterService(b *eventingv1alpha1.Broker) *corev1.Service { diff --git a/pkg/provisioners/namespace/reconcile.go b/pkg/reconciler/v1alpha1/namespace/namespace.go similarity index 60% rename from pkg/provisioners/namespace/reconcile.go rename to pkg/reconciler/v1alpha1/namespace/namespace.go index cc2b2913010..8fad590ecce 100644 --- a/pkg/provisioners/namespace/reconcile.go +++ b/pkg/reconciler/v1alpha1/namespace/namespace.go @@ -1,5 +1,5 @@ /* -Copyright 2018 The Knative Authors +Copyright 2019 The Knative Authors Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -18,19 +18,32 @@ package namespace import ( "context" - "github.com/knative/eventing/contrib/gcppubsub/pkg/util/logging" "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" "go.uber.org/zap" + "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" k8serrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/dynamic" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/record" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller" + "sigs.k8s.io/controller-runtime/pkg/handler" + "sigs.k8s.io/controller-runtime/pkg/manager" "sigs.k8s.io/controller-runtime/pkg/reconcile" + "sigs.k8s.io/controller-runtime/pkg/source" ) const ( + // controllerAgentName is the string used by this controller to identify + // itself when creating events. + controllerAgentName = "knative-eventing-namespace-controller" + defaultBroker = "default" knativeEventingAnnotation = "eventing.knative.dev/injection" @@ -38,6 +51,81 @@ const ( brokerCreated = "BrokerCreated" ) +type reconciler struct { + client client.Client + restConfig *rest.Config + dynamicClient dynamic.Interface + recorder record.EventRecorder + + logger *zap.Logger +} + +// Verify the struct implements reconcile.Reconciler +var _ reconcile.Reconciler = &reconciler{} + +// ProvideController returns a function that returns a Broker controller. +func ProvideController(logger *zap.Logger) func(manager.Manager) (controller.Controller, error) { + return func(mgr manager.Manager) (controller.Controller, error) { + // Setup a new controller to Reconcile Brokers. + r := &reconciler{ + recorder: mgr.GetRecorder(controllerAgentName), + logger: logger, + } + c, err := controller.New(controllerAgentName, mgr, controller.Options{ + Reconciler: r, + }) + if err != nil { + return nil, err + } + + // Watch Namespaces. + if err = c.Watch(&source.Kind{Type: &v1.Namespace{}}, &handler.EnqueueRequestForObject{}); err != nil { + return nil, err + } + + // Watch all the resources that this reconciler reconciles. + if err = c.Watch(&source.Kind{Type: &v1alpha1.Broker{}}, &handler.EnqueueRequestsFromMapFunc{ToRequests: &namespaceMapper{}}); err != nil { + return nil, err + } + + for _, t := range []runtime.Object{ &v1alpha1.Broker{} } { + err = c.Watch(&source.Kind{Type: t}, &handler.EnqueueRequestsFromMapFunc{ToRequests: &namespaceMapper{}}); + if err != nil { + return nil, err + } + } + + return c, nil + } +} + +type namespaceMapper struct{} + +var _ handler.Mapper = &namespaceMapper{} + +func (namespaceMapper) Map(o handler.MapObject) []reconcile.Request { + return []reconcile.Request{ + { + NamespacedName: types.NamespacedName{ + Namespace: "", + Name: o.Meta.GetNamespace(), + }, + }, + } +} + +func (r *reconciler) InjectClient(c client.Client) error { + r.client = c + return nil +} + +func (r *reconciler) InjectConfig(c *rest.Config) error { + r.restConfig = c + var err error + r.dynamicClient, err = dynamic.NewForConfig(c) + return err +} + // Reconcile compares the actual state with the desired, and attempts to // converge the two. It then updates the Status block of the Trigger resource // with the current status of the resource. @@ -103,7 +191,7 @@ func (r *reconciler) getBroker(ctx context.Context, ns *corev1.Namespace) (*v1al func (r *reconciler) reconcileBroker(ctx context.Context, ns *corev1.Namespace) (*v1alpha1.Broker, error) { current, err := r.getBroker(ctx, ns) - // If the resource doesn't exist, we'll create it + // If the resource doesn't exist, we'll create it. if k8serrors.IsNotFound(err) { b := newBroker(ns) err = r.client.Create(ctx, b) diff --git a/pkg/reconciler/v1alpha1/trigger/trigger.go b/pkg/reconciler/v1alpha1/trigger/trigger.go index d7ce3cf2c37..8c2d57b26d9 100644 --- a/pkg/reconciler/v1alpha1/trigger/trigger.go +++ b/pkg/reconciler/v1alpha1/trigger/trigger.go @@ -19,6 +19,7 @@ package trigger import ( "context" "fmt" + "k8s.io/apimachinery/pkg/runtime" "k8s.io/client-go/dynamic" "k8s.io/client-go/rest" @@ -87,11 +88,23 @@ func ProvideController(logger *zap.Logger) func(manager.Manager) (controller.Con return nil, err } - // Watch Subscription events and enqueue Subscription object key. + // Watch Triggers. if err = c.Watch(&source.Kind{Type: &v1alpha1.Trigger{}}, &handler.EnqueueRequestForObject{}); err != nil { return nil, err } + // Watch all the resources that the Trigger reconciles. + for _, t := range []runtime.Object{ &corev1.Service{}, &istiov1alpha3.VirtualService{}, &v1alpha1.Subscription{} } { + err = c.Watch(&source.Kind{Type: t}, &handler.EnqueueRequestForOwner{OwnerType: &v1alpha1.Broker{}, IsController: true}) + if err != nil { + return nil, err + } + } + + // TODO reconcile after a Broker change. This might require keeping a map from Broker -> []Trigger. + // TODO reconcile after a change to the subscriber. I'm not sure how this is possible, but we should do it if we + // can find a way. + return c, nil } } From 3a3c13c853f6c572fb78409c95a97c835a2ac21c Mon Sep 17 00:00:00 2001 From: Adam Harwayne Date: Tue, 12 Feb 2019 16:25:11 -0800 Subject: [PATCH 042/221] PR comment. --- pkg/reconciler/v1alpha1/namespace/namespace.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/reconciler/v1alpha1/namespace/namespace.go b/pkg/reconciler/v1alpha1/namespace/namespace.go index 8fad590ecce..078a3590a2d 100644 --- a/pkg/reconciler/v1alpha1/namespace/namespace.go +++ b/pkg/reconciler/v1alpha1/namespace/namespace.go @@ -47,7 +47,7 @@ const ( defaultBroker = "default" knativeEventingAnnotation = "eventing.knative.dev/injection" - // Name of the corev1.Events emitted from the reconciliation process + // Name of the corev1.Events emitted from the reconciliation process. brokerCreated = "BrokerCreated" ) From f834f8927622ba3784381977683048d8667bb04a Mon Sep 17 00:00:00 2001 From: Adam Harwayne Date: Tue, 12 Feb 2019 16:50:12 -0800 Subject: [PATCH 043/221] Remove redundant watch. --- pkg/reconciler/v1alpha1/namespace/namespace.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pkg/reconciler/v1alpha1/namespace/namespace.go b/pkg/reconciler/v1alpha1/namespace/namespace.go index 078a3590a2d..6862a1a8c5c 100644 --- a/pkg/reconciler/v1alpha1/namespace/namespace.go +++ b/pkg/reconciler/v1alpha1/namespace/namespace.go @@ -84,10 +84,6 @@ func ProvideController(logger *zap.Logger) func(manager.Manager) (controller.Con } // Watch all the resources that this reconciler reconciles. - if err = c.Watch(&source.Kind{Type: &v1alpha1.Broker{}}, &handler.EnqueueRequestsFromMapFunc{ToRequests: &namespaceMapper{}}); err != nil { - return nil, err - } - for _, t := range []runtime.Object{ &v1alpha1.Broker{} } { err = c.Watch(&source.Kind{Type: t}, &handler.EnqueueRequestsFromMapFunc{ToRequests: &namespaceMapper{}}); if err != nil { From 6b817ef8db4894a837aab7b2d27da13ddb0f804c Mon Sep 17 00:00:00 2001 From: Adam Harwayne Date: Tue, 12 Feb 2019 17:10:39 -0800 Subject: [PATCH 044/221] Unit test scaffold. --- pkg/broker/receiver_test.go | 25 +---- pkg/reconciler/v1alpha1/broker/broker_test.go | 91 +++++++++++++++++++ .../v1alpha1/namespace/namespace_test.go | 91 +++++++++++++++++++ .../v1alpha1/trigger/trigger_test.go | 91 +++++++++++++++++++ 4 files changed, 275 insertions(+), 23 deletions(-) create mode 100644 pkg/reconciler/v1alpha1/broker/broker_test.go create mode 100644 pkg/reconciler/v1alpha1/namespace/namespace_test.go create mode 100644 pkg/reconciler/v1alpha1/trigger/trigger_test.go diff --git a/pkg/broker/receiver_test.go b/pkg/broker/receiver_test.go index 2dead920105..aa553399351 100644 --- a/pkg/broker/receiver_test.go +++ b/pkg/broker/receiver_test.go @@ -18,7 +18,6 @@ package broker import ( "context" - "errors" "net/http/httptest" "strings" "testing" @@ -28,10 +27,9 @@ import ( eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" "k8s.io/client-go/kubernetes/scheme" - "github.com/knative/eventing/contrib/gcppubsub/pkg/util/fakepubsub" "go.uber.org/zap" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "sigs.k8s.io/controller-runtime/pkg/client/fake" @@ -63,7 +61,6 @@ func init() { func TestReceiver(t *testing.T) { testCases := map[string]struct { initialState []runtime.Object - pubSubData fakepubsub.CreatorData expectedErr bool }{ "can't get channel": { @@ -98,9 +95,6 @@ func TestReceiver(t *testing.T) { testcreds.MakeSecretWithCreds(), makeChannel(), }, - pubSubData: fakepubsub.CreatorData{ - ClientCreateErr: errors.New("testInducedError"), - }, expectedErr: true, }, "Publish fails": { @@ -108,23 +102,8 @@ func TestReceiver(t *testing.T) { testcreds.MakeSecretWithCreds(), makeChannel(), }, - pubSubData: fakepubsub.CreatorData{ - ClientData: fakepubsub.ClientData{ - TopicData: fakepubsub.TopicData{ - Publish: fakepubsub.PublishResultData{ - Err: errors.New("testInducedError"), - }, - }, - }, - }, expectedErr: true, }, - "Publish succeeds": { - initialState: []runtime.Object{ - testcreds.MakeSecretWithCreds(), - makeChannel(), - }, - }, } for n, tc := range testCases { t.Run(n, func(t *testing.T) { @@ -133,7 +112,7 @@ func TestReceiver(t *testing.T) { fake.NewFakeClient(tc.initialState...)) resp := httptest.NewRecorder() req := httptest.NewRequest("POST", "/", strings.NewReader(validMessage)) - req.Host = "test-channel.test-namespace.channels.cluster.local" + req.Host = "test-trigger.test-namespace.triggers.cluster.local" mr.newMessageReceiver().HandleRequest(resp, req) if tc.expectedErr { if resp.Result().StatusCode >= 200 && resp.Result().StatusCode < 300 { diff --git a/pkg/reconciler/v1alpha1/broker/broker_test.go b/pkg/reconciler/v1alpha1/broker/broker_test.go new file mode 100644 index 00000000000..7a887c44284 --- /dev/null +++ b/pkg/reconciler/v1alpha1/broker/broker_test.go @@ -0,0 +1,91 @@ +/* +Copyright 2019 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT 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 broker + +import ( + "github.com/google/go-cmp/cmp" + "k8s.io/client-go/dynamic" + "k8s.io/client-go/rest" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + "testing" +) + +func TestProvideController(t *testing.T) { + //TODO(grantr) This needs a mock of manager.Manager. Creating a manager + // with a fake Config fails because the Manager tries to contact the + // apiserver. + + // cfg := &rest.Config{ + // Host: "http://foo:80", + // } + // + // mgr, err := manager.New(cfg, manager.Options{}) + // if err != nil { + // t.Fatalf("Error creating manager: %v", err) + // } + // + // _, err = ProvideController(mgr) + // if err != nil { + // t.Fatalf("Error in ProvideController: %v", err) + // } +} + +func TestInjectClient(t *testing.T) { + r := &reconciler{} + orig := r.client + n := fake.NewFakeClient() + if orig == n { + t.Errorf("Original and new clients are identical: %v", orig) + } + err := r.InjectClient(n) + if err != nil { + t.Errorf("Unexpected error injecting the client: %v", err) + } + if n != r.client { + t.Errorf("Unexpected client. Expected: '%v'. Actual: '%v'", n, r.client) + } +} + +func TestInjectConfig(t *testing.T) { + r := &reconciler{} + wantCfg := &rest.Config{ + Host: "http://foo", + } + + err := r.InjectConfig(wantCfg) + if err != nil { + t.Fatalf("Unexpected error injecting the config: %v", err) + } + + gotCfg := r.restConfig + if diff := cmp.Diff(wantCfg, gotCfg); diff != "" { + t.Errorf("Unexpected config (-want, +got): %v", diff) + } + + wantDynClient, err := dynamic.NewForConfig(wantCfg) + if err != nil { + t.Fatalf("Unexpected error generating dynamic client: %v", err) + } + + // Since dynamicClient doesn't export any fields, we can only test its type. + switch r.dynamicClient.(type) { + case dynamic.Interface: + // ok + default: + t.Errorf("Unexpected dynamicClient type. Expected: %T, Got: %T", wantDynClient, r.dynamicClient) + } +} diff --git a/pkg/reconciler/v1alpha1/namespace/namespace_test.go b/pkg/reconciler/v1alpha1/namespace/namespace_test.go new file mode 100644 index 00000000000..29885f24d97 --- /dev/null +++ b/pkg/reconciler/v1alpha1/namespace/namespace_test.go @@ -0,0 +1,91 @@ +/* +Copyright 2019 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT 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 namespace + +import ( + "github.com/google/go-cmp/cmp" + "k8s.io/client-go/dynamic" + "k8s.io/client-go/rest" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + "testing" +) + +func TestProvideController(t *testing.T) { + //TODO(grantr) This needs a mock of manager.Manager. Creating a manager + // with a fake Config fails because the Manager tries to contact the + // apiserver. + + // cfg := &rest.Config{ + // Host: "http://foo:80", + // } + // + // mgr, err := manager.New(cfg, manager.Options{}) + // if err != nil { + // t.Fatalf("Error creating manager: %v", err) + // } + // + // _, err = ProvideController(mgr) + // if err != nil { + // t.Fatalf("Error in ProvideController: %v", err) + // } +} + +func TestInjectClient(t *testing.T) { + r := &reconciler{} + orig := r.client + n := fake.NewFakeClient() + if orig == n { + t.Errorf("Original and new clients are identical: %v", orig) + } + err := r.InjectClient(n) + if err != nil { + t.Errorf("Unexpected error injecting the client: %v", err) + } + if n != r.client { + t.Errorf("Unexpected client. Expected: '%v'. Actual: '%v'", n, r.client) + } +} + +func TestInjectConfig(t *testing.T) { + r := &reconciler{} + wantCfg := &rest.Config{ + Host: "http://foo", + } + + err := r.InjectConfig(wantCfg) + if err != nil { + t.Fatalf("Unexpected error injecting the config: %v", err) + } + + gotCfg := r.restConfig + if diff := cmp.Diff(wantCfg, gotCfg); diff != "" { + t.Errorf("Unexpected config (-want, +got): %v", diff) + } + + wantDynClient, err := dynamic.NewForConfig(wantCfg) + if err != nil { + t.Fatalf("Unexpected error generating dynamic client: %v", err) + } + + // Since dynamicClient doesn't export any fields, we can only test its type. + switch r.dynamicClient.(type) { + case dynamic.Interface: + // ok + default: + t.Errorf("Unexpected dynamicClient type. Expected: %T, Got: %T", wantDynClient, r.dynamicClient) + } +} diff --git a/pkg/reconciler/v1alpha1/trigger/trigger_test.go b/pkg/reconciler/v1alpha1/trigger/trigger_test.go new file mode 100644 index 00000000000..298a3a48f5c --- /dev/null +++ b/pkg/reconciler/v1alpha1/trigger/trigger_test.go @@ -0,0 +1,91 @@ +/* +Copyright 2019 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT 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 trigger + +import ( + "github.com/google/go-cmp/cmp" + "k8s.io/client-go/dynamic" + "k8s.io/client-go/rest" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + "testing" +) + +func TestProvideController(t *testing.T) { + //TODO(grantr) This needs a mock of manager.Manager. Creating a manager + // with a fake Config fails because the Manager tries to contact the + // apiserver. + + // cfg := &rest.Config{ + // Host: "http://foo:80", + // } + // + // mgr, err := manager.New(cfg, manager.Options{}) + // if err != nil { + // t.Fatalf("Error creating manager: %v", err) + // } + // + // _, err = ProvideController(mgr) + // if err != nil { + // t.Fatalf("Error in ProvideController: %v", err) + // } +} + +func TestInjectClient(t *testing.T) { + r := &reconciler{} + orig := r.client + n := fake.NewFakeClient() + if orig == n { + t.Errorf("Original and new clients are identical: %v", orig) + } + err := r.InjectClient(n) + if err != nil { + t.Errorf("Unexpected error injecting the client: %v", err) + } + if n != r.client { + t.Errorf("Unexpected client. Expected: '%v'. Actual: '%v'", n, r.client) + } +} + +func TestInjectConfig(t *testing.T) { + r := &reconciler{} + wantCfg := &rest.Config{ + Host: "http://foo", + } + + err := r.InjectConfig(wantCfg) + if err != nil { + t.Fatalf("Unexpected error injecting the config: %v", err) + } + + gotCfg := r.restConfig + if diff := cmp.Diff(wantCfg, gotCfg); diff != "" { + t.Errorf("Unexpected config (-want, +got): %v", diff) + } + + wantDynClient, err := dynamic.NewForConfig(wantCfg) + if err != nil { + t.Fatalf("Unexpected error generating dynamic client: %v", err) + } + + // Since dynamicClient doesn't export any fields, we can only test its type. + switch r.dynamicClient.(type) { + case dynamic.Interface: + // ok + default: + t.Errorf("Unexpected dynamicClient type. Expected: %T, Got: %T", wantDynClient, r.dynamicClient) + } +} From 97e642d7dc7b7fca81a24610a973c4c3ebe052b3 Mon Sep 17 00:00:00 2001 From: Adam Harwayne Date: Tue, 12 Feb 2019 22:19:29 -0800 Subject: [PATCH 045/221] Tests for the namespace reconciler. --- .../v1alpha1/namespace/namespace.go | 2 +- .../v1alpha1/namespace/namespace_test.go | 225 ++++++++++++++++++ 2 files changed, 226 insertions(+), 1 deletion(-) diff --git a/pkg/reconciler/v1alpha1/namespace/namespace.go b/pkg/reconciler/v1alpha1/namespace/namespace.go index 6862a1a8c5c..1c2c31ca618 100644 --- a/pkg/reconciler/v1alpha1/namespace/namespace.go +++ b/pkg/reconciler/v1alpha1/namespace/namespace.go @@ -45,7 +45,7 @@ const ( controllerAgentName = "knative-eventing-namespace-controller" defaultBroker = "default" - knativeEventingAnnotation = "eventing.knative.dev/injection" + knativeEventingAnnotation = "eventing.knative.dev/inject" // Name of the corev1.Events emitted from the reconciliation process. brokerCreated = "BrokerCreated" diff --git a/pkg/reconciler/v1alpha1/namespace/namespace_test.go b/pkg/reconciler/v1alpha1/namespace/namespace_test.go index 29885f24d97..cdf1876ac29 100644 --- a/pkg/reconciler/v1alpha1/namespace/namespace_test.go +++ b/pkg/reconciler/v1alpha1/namespace/namespace_test.go @@ -17,13 +17,46 @@ limitations under the License. package namespace import ( + "context" + "errors" + "fmt" "github.com/google/go-cmp/cmp" + "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" + controllertesting "github.com/knative/eventing/pkg/reconciler/testing" + "go.uber.org/zap" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/dynamic" + "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/rest" + "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" + "sigs.k8s.io/controller-runtime/pkg/handler" + "sigs.k8s.io/controller-runtime/pkg/reconcile" "testing" ) +const ( + testNS = "test-namespace" + brokerName = "default" +) + +var ( + falseString = "false" + trueString = "true" + + // deletionTime is used when objects are marked as deleted. Rfc3339Copy() + // truncates to seconds to match the loss of precision during serialization. + deletionTime = metav1.Now().Rfc3339Copy() +) + +func init() { + // Add types to scheme + v1alpha1.AddToScheme(scheme.Scheme) +} + func TestProvideController(t *testing.T) { //TODO(grantr) This needs a mock of manager.Manager. Creating a manager // with a fake Config fails because the Manager tries to contact the @@ -89,3 +122,195 @@ func TestInjectConfig(t *testing.T) { t.Errorf("Unexpected dynamicClient type. Expected: %T, Got: %T", wantDynClient, r.dynamicClient) } } + +func TestNamespaceMapper_Map(t *testing.T) { + m := &namespaceMapper{} + + req := handler.MapObject{ + Meta: makeBroker().GetObjectMeta(), + Object: makeBroker(), + } + actual := m.Map(req) + expected := []reconcile.Request{ + { + NamespacedName: types.NamespacedName{ + Namespace: "", + Name: testNS, + }, + }, + } + if diff := cmp.Diff(expected, actual); diff != "" { + t.Errorf("Unexpected reconcile requests (-want +got): %v", diff) + } +} + +func TestReconcile(t *testing.T) { + testCases := []controllertesting.TestCase{ + { + Name: "Namespace not found", + }, + { + Name: "Namespace get fails", + Scheme: scheme.Scheme, + Mocks: controllertesting.Mocks{ + MockGets: []controllertesting.MockGet{ + func(_ client.Client, _ context.Context, _ client.ObjectKey, obj runtime.Object) (controllertesting.MockHandled, error) { + if _, ok := obj.(*corev1.Namespace); ok { + return controllertesting.Handled, errors.New("test error getting the NS") + } + return controllertesting.Unhandled, nil + }, + }, + }, + WantErrMsg: "test error getting the NS", + }, + { + Name: "Namespace is not annotated", + Scheme: scheme.Scheme, + InitialState: []runtime.Object{ + makeNamespace(nil), + }, + WantAbsent: []runtime.Object{ + makeBroker(), + }, + }, + { + Name: "Namespace is annotated off", + Scheme: scheme.Scheme, + InitialState: []runtime.Object{ + makeNamespace(&falseString), + }, + WantAbsent: []runtime.Object{ + makeBroker(), + }, + }, + { + Name: "Namespace is being deleted", + Scheme: scheme.Scheme, + InitialState: []runtime.Object{ + makeDeletingNamespace(), + }, + WantAbsent: []runtime.Object{ + makeBroker(), + }, + }, + { + Name: "Broker.Get fails", + Scheme: scheme.Scheme, + InitialState: []runtime.Object{ + makeNamespace(&trueString), + }, + Mocks: controllertesting.Mocks{ + MockGets: []controllertesting.MockGet{ + func(_ client.Client, _ context.Context, _ client.ObjectKey, obj runtime.Object) (controllertesting.MockHandled, error) { + if _, ok := obj.(*v1alpha1.Broker); ok { + return controllertesting.Handled, errors.New("test error getting the Broker") + } + return controllertesting.Unhandled, nil + }, + }, + }, + WantErrMsg: "test error getting the Broker", + WantAbsent: []runtime.Object{ + makeBroker(), + }, + }, + { + Name: "Broker Found", + Scheme: scheme.Scheme, + InitialState: []runtime.Object{ + makeNamespace(&trueString), + makeBroker(), + }, + }, + { + Name: "Broker.Create fails", + Scheme: scheme.Scheme, + InitialState: []runtime.Object{ + makeNamespace(&trueString), + }, + Mocks: controllertesting.Mocks{ + MockCreates: []controllertesting.MockCreate{ + func(_ client.Client, _ context.Context, obj runtime.Object) (controllertesting.MockHandled, error) { + if _, ok := obj.(*v1alpha1.Broker); ok { + return controllertesting.Handled, errors.New("test error creating the Broker") + } + return controllertesting.Unhandled, nil + }, + }, + }, + WantErrMsg: "test error creating the Broker", + }, + { + Name: "Broker created", + Scheme: scheme.Scheme, + InitialState: []runtime.Object{ + makeNamespace(&trueString), + }, + WantPresent: []runtime.Object{ + makeBroker(), + }, + WantEvent: []corev1.Event{ + { + Reason: brokerCreated, Type: corev1.EventTypeNormal, + }, + }, + }, + } + for _, tc := range testCases { + c := tc.GetClient() + dc := tc.GetDynamicClient() + recorder := tc.GetEventRecorder() + + r := &reconciler{ + client: c, + dynamicClient: dc, + restConfig: &rest.Config{}, + recorder: recorder, + logger: zap.NewNop(), + } + tc.ReconcileKey = fmt.Sprintf("%s/%s", "", testNS) + tc.IgnoreTimes = true + t.Run(tc.Name, tc.Runner(t, r, c, recorder)) + } +} + +func makeNamespace(annotationValue *string) *corev1.Namespace { + annotations := map[string]string{} + if annotationValue != nil { + annotations["eventing.knative.dev/inject"] = *annotationValue + } + + return &corev1.Namespace{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "v1", + Kind: "Namespace", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: testNS, + Annotations: annotations, + }, + } +} + +func makeDeletingNamespace() *corev1.Namespace { + ns := makeNamespace(&trueString) + ns.DeletionTimestamp = &deletionTime + return ns +} + +func makeBroker() *v1alpha1.Broker { + return &v1alpha1.Broker{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "eventing.knative.dev/v1alpha1", + Kind: "Broker", + }, + ObjectMeta: metav1.ObjectMeta{ + Namespace: testNS, + Name: brokerName, + Labels: map[string]string{ + "eventing.knative.dev/brokerForNamespace": "true", + }, + }, + } +} From da32baeecd280940dffdacd931ea6952cb8d1e49 Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Tue, 12 Feb 2019 23:28:23 -0800 Subject: [PATCH 046/221] Exact matching for filters without using k8s selectors-based syntax. The matching can only be done on source and type for now. --- Gopkg.lock | 1 - .../eventing/v1alpha1/trigger_defaults.go | 7 +- pkg/apis/eventing/v1alpha1/trigger_types.go | 13 ++-- .../eventing/v1alpha1/trigger_validation.go | 2 +- .../v1alpha1/zz_generated.deepcopy.go | 68 +++++++++--------- pkg/broker/receiver.go | 69 ++++--------------- t.yaml | 1 - t2.yaml | 6 +- t3.yaml | 6 +- 9 files changed, 64 insertions(+), 109 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index 288846af8fd..5238ff27d50 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -1255,7 +1255,6 @@ "k8s.io/apimachinery/pkg/runtime", "k8s.io/apimachinery/pkg/runtime/schema", "k8s.io/apimachinery/pkg/runtime/serializer", - "k8s.io/apimachinery/pkg/selection", "k8s.io/apimachinery/pkg/types", "k8s.io/apimachinery/pkg/util/intstr", "k8s.io/apimachinery/pkg/util/sets", diff --git a/pkg/apis/eventing/v1alpha1/trigger_defaults.go b/pkg/apis/eventing/v1alpha1/trigger_defaults.go index d996d5ea30d..fe5e7bbf797 100644 --- a/pkg/apis/eventing/v1alpha1/trigger_defaults.go +++ b/pkg/apis/eventing/v1alpha1/trigger_defaults.go @@ -16,8 +16,6 @@ limitations under the License. package v1alpha1 -import v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - func (t *Trigger) SetDefaults() { t.Spec.SetDefaults() } @@ -26,9 +24,8 @@ func (ts *TriggerSpec) SetDefaults() { if ts.Broker == "" { ts.Broker = "default" } - // Make empty filter selector so that we allow everything. + // Make a default filter that allows anything. if ts.Filter == nil { - ts.Filter = &FilterSelector{map[string]string{}, - []v1.LabelSelectorRequirement{}} + ts.Filter = &TriggerFilter{TriggerFilterAttributes{Type: "", Source: ""}} } } diff --git a/pkg/apis/eventing/v1alpha1/trigger_types.go b/pkg/apis/eventing/v1alpha1/trigger_types.go index 75131366d6d..63be349e13d 100644 --- a/pkg/apis/eventing/v1alpha1/trigger_types.go +++ b/pkg/apis/eventing/v1alpha1/trigger_types.go @@ -61,15 +61,18 @@ type TriggerSpec struct { Broker string `json:"broker,omitempty"` // +optional - Filter *FilterSelector `json:"filter,omitempty"` + Filter *TriggerFilter `json:"filter,omitempty"` Subscriber *SubscriberSpec `json:"subscriber,omitempty"` } -type FilterSelector struct { - Attributes map[string]string `json:"attributes,omitempty" protobuf:"bytes,1,rep,name=attributes"` - // TODO create our own FilterSelectorRequirement - AttributeExpressions []metav1.LabelSelectorRequirement `json:"attributeExpressions,omitempty" protobuf:"bytes,2,rep,name=attributeExpressions"` +type TriggerFilter struct { + ExactMatch TriggerFilterAttributes `json:"exactMatch,omitempty"` +} + +type TriggerFilterAttributes struct { + Type string `json:"type,omitempty"` + Source string `json:"source,omitempty"` } var triggerCondSet = duckv1alpha1.NewLivingConditionSet(TriggerConditionBrokerExists, TriggerConditionKubernetesService, TriggerConditionVirtualService, TriggerConditionSubscribed) diff --git a/pkg/apis/eventing/v1alpha1/trigger_validation.go b/pkg/apis/eventing/v1alpha1/trigger_validation.go index 42057cf9bef..fdf3a9ff08b 100644 --- a/pkg/apis/eventing/v1alpha1/trigger_validation.go +++ b/pkg/apis/eventing/v1alpha1/trigger_validation.go @@ -33,7 +33,7 @@ func (ts *TriggerSpec) Validate() *apis.FieldError { } if ts.Filter == nil { - fe := apis.ErrMissingField("filters") + fe := apis.ErrMissingField("filter") errs = errs.Also(fe) } diff --git a/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go index 1672ffe6dc9..88e1c446671 100644 --- a/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go @@ -24,7 +24,6 @@ import ( apis_duck_v1alpha1 "github.com/knative/eventing/pkg/apis/duck/v1alpha1" duck_v1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" v1 "k8s.io/api/core/v1" - meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" ) @@ -375,36 +374,6 @@ func (in *ClusterChannelProvisionerStatus) DeepCopy() *ClusterChannelProvisioner return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FilterSelector) DeepCopyInto(out *FilterSelector) { - *out = *in - if in.Attributes != nil { - in, out := &in.Attributes, &out.Attributes - *out = make(map[string]string, len(*in)) - for key, val := range *in { - (*out)[key] = val - } - } - if in.AttributeExpressions != nil { - in, out := &in.AttributeExpressions, &out.AttributeExpressions - *out = make([]meta_v1.LabelSelectorRequirement, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FilterSelector. -func (in *FilterSelector) DeepCopy() *FilterSelector { - if in == nil { - return nil - } - out := new(FilterSelector) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ReplyStrategy) DeepCopyInto(out *ReplyStrategy) { *out = *in @@ -628,6 +597,39 @@ func (in *Trigger) DeepCopyObject() runtime.Object { 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 + out.ExactMatch = in.ExactMatch + 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) { + *out = *in + 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 @@ -669,8 +671,8 @@ func (in *TriggerSpec) DeepCopyInto(out *TriggerSpec) { if *in == nil { *out = nil } else { - *out = new(FilterSelector) - (*in).DeepCopyInto(*out) + *out = new(TriggerFilter) + **out = **in } } if in.Subscriber != nil { diff --git a/pkg/broker/receiver.go b/pkg/broker/receiver.go index ea009b05f6b..4b4cfe89136 100644 --- a/pkg/broker/receiver.go +++ b/pkg/broker/receiver.go @@ -19,22 +19,19 @@ package broker import ( "context" "errors" - "fmt" - "reflect" - "unsafe" - - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/selection" eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" "github.com/knative/eventing/pkg/provisioners" "go.uber.org/zap" - "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/manager" ) +const ( + Any = "" +) + // Receiver parses Cloud Events and sends them to the channel. type Receiver struct { logger *zap.Logger @@ -100,56 +97,16 @@ func (r *Receiver) getTrigger(ctx context.Context, ref provisioners.ChannelRefer return t, err } -func (r *Receiver) shouldSendMessage(t *eventingv1alpha1.TriggerSpec, m *provisioners.Message) bool { - // This conversion to selector should be done only once, possibly upon creation of the trigger - // in case the filters are immutable. All validations should be performed then. - selector, err := r.buildSelector(t) - if err != nil { - r.logger.Error("Invalid selector for trigger spec", zap.Any("triggerSpec", t)) +func (r *Receiver) shouldSendMessage(ts *eventingv1alpha1.TriggerSpec, m *provisioners.Message) bool { + filterType := ts.Filter.ExactMatch.Type + if filterType != Any && filterType != m.Headers["Ce-Eventtype"] { + r.logger.Debug("Wrong type", zap.String("trigger.spec.filter.exactMatch.type", filterType), zap.String("message.type", m.Headers["Ce-Eventtype"])) return false } - matched := selector.Matches(labels.Set(m.Headers)) - if !matched { - r.logger.Debug("Selector did not match message headers", zap.String("selector", selector.String()), zap.Any("headers", m.Headers)) - } - return matched -} - -func (r *Receiver) buildSelector(ts *eventingv1alpha1.TriggerSpec) (labels.Selector, error) { - // Avoid validation of keys and values, otherwise we cannot use LabelSelectors. - // Eventually, we will need to create our own Selector implementation with our own Requirement struct. - selector := labels.SelectorFromValidatedSet(labels.Set(ts.Filter.Attributes)) - for _, expr := range ts.Filter.AttributeExpressions { - var op selection.Operator - switch expr.Operator { - case v1.LabelSelectorOpIn: - op = selection.In - case v1.LabelSelectorOpNotIn: - op = selection.NotIn - case v1.LabelSelectorOpExists: - op = selection.Exists - case v1.LabelSelectorOpDoesNotExist: - op = selection.DoesNotExist - default: - return nil, fmt.Errorf("%q is not a valid filter selector operator", expr.Operator) - } - // Hack to set Requirement's unexposed fields to easily support expressions using k8s LabelSelectors. - // We should change this once we agree on a filter API. - r := labels.Requirement{} - rr := reflect.ValueOf(&r).Elem() - // Setting key - rrKey := rr.FieldByName("key") - rrKey = reflect.NewAt(rrKey.Type(), unsafe.Pointer(rrKey.UnsafeAddr())).Elem() - rrKey.SetString(expr.Key) - // Setting operator - rrOperator := rr.FieldByName("operator") - rrOperator = reflect.NewAt(rrOperator.Type(), unsafe.Pointer(rrOperator.UnsafeAddr())).Elem() - rrOperator.Set(reflect.ValueOf(op)) - // Setting strValues - rrStrValues := rr.FieldByName("strValues") - rrStrValues = reflect.NewAt(rrStrValues.Type(), unsafe.Pointer(rrStrValues.UnsafeAddr())).Elem() - rrStrValues.Set(reflect.ValueOf(expr.Values)) - selector = selector.Add(r) + filterSource := ts.Filter.ExactMatch.Source + if filterSource != Any && filterSource != m.Headers["Ce-Source"] { + r.logger.Debug("Wrong source", zap.String("trigger.spec.filter.exactMatch.source", filterSource), zap.String("message.source", m.Headers["Ce-Source"])) + return false } - return selector, nil + return true } diff --git a/t.yaml b/t.yaml index d9427cc9552..0e2604dd595 100644 --- a/t.yaml +++ b/t.yaml @@ -3,7 +3,6 @@ kind: Trigger metadata: name: t spec: - filter: {} subscriber: ref: apiVersion: serving.knative.dev/v1alpha1 diff --git a/t2.yaml b/t2.yaml index c95018d4bfb..6274a6166b4 100644 --- a/t2.yaml +++ b/t2.yaml @@ -6,9 +6,9 @@ spec: # Our Cloud Event parsing library seems to have a bug and forces to put type and source in double # quotes (as it thinks the actual value is `"foo"`, not `foo`). filter: - attributes: - Ce-Eventtype: '"com.example.someevent"' - Ce-Source: '"/mycontext/subcontext"' + exactMatch: + type: '"com.example.someevent"' + source: '"/mycontext/subcontext"' subscriber: ref: apiVersion: serving.knative.dev/v1alpha1 diff --git a/t3.yaml b/t3.yaml index 1a90d86926b..f286ea7d1ec 100644 --- a/t3.yaml +++ b/t3.yaml @@ -6,10 +6,8 @@ spec: # Our Cloud Event parsing library seems to have a bug and forces to put type and source in double # quotes (as it thinks the actual value is `"foo"`, not `foo`). filter: - attributes: - Ce-Source: '"/mycontext/subcontext"' - attributeExpressions: - - {key: Ce-Eventtype, operator: In, values: ['"com.example.someevent"', '"com.example.someevent1"']} + exactMatch: + source: '"/mycontext/subcontext"' subscriber: ref: apiVersion: serving.knative.dev/v1alpha1 From 8ccfcca4e5261fbee61ffdb3dd61d320f0057c9b Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Tue, 12 Feb 2019 23:34:30 -0800 Subject: [PATCH 047/221] Removing t3 as we don't have set expressions --- t3.yaml | 15 --------------- 1 file changed, 15 deletions(-) delete mode 100644 t3.yaml diff --git a/t3.yaml b/t3.yaml deleted file mode 100644 index f286ea7d1ec..00000000000 --- a/t3.yaml +++ /dev/null @@ -1,15 +0,0 @@ -apiVersion: eventing.knative.dev/v1alpha1 -kind: Trigger -metadata: - name: t -spec: - # Our Cloud Event parsing library seems to have a bug and forces to put type and source in double - # quotes (as it thinks the actual value is `"foo"`, not `foo`). - filter: - exactMatch: - source: '"/mycontext/subcontext"' - subscriber: - ref: - apiVersion: serving.knative.dev/v1alpha1 - kind: Service - name: message-dumper From 29acf36937d69245dddf39f84cdf0e7f434ea96b Mon Sep 17 00:00:00 2001 From: nachocano Date: Wed, 13 Feb 2019 11:34:51 -0800 Subject: [PATCH 048/221] Updates after code review --- pkg/apis/eventing/v1alpha1/trigger_defaults.go | 2 +- pkg/apis/eventing/v1alpha1/trigger_types.go | 5 ++++- pkg/apis/eventing/v1alpha1/trigger_validation.go | 5 +++++ pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go | 12 ++++++++++-- pkg/broker/receiver.go | 8 ++------ 5 files changed, 22 insertions(+), 10 deletions(-) diff --git a/pkg/apis/eventing/v1alpha1/trigger_defaults.go b/pkg/apis/eventing/v1alpha1/trigger_defaults.go index fe5e7bbf797..e3dd6c32818 100644 --- a/pkg/apis/eventing/v1alpha1/trigger_defaults.go +++ b/pkg/apis/eventing/v1alpha1/trigger_defaults.go @@ -26,6 +26,6 @@ func (ts *TriggerSpec) SetDefaults() { } // Make a default filter that allows anything. if ts.Filter == nil { - ts.Filter = &TriggerFilter{TriggerFilterAttributes{Type: "", Source: ""}} + ts.Filter = &TriggerFilter{&TriggerFilterAttributes{Type: TriggerAnyFilter, Source: TriggerAnyFilter}} } } diff --git a/pkg/apis/eventing/v1alpha1/trigger_types.go b/pkg/apis/eventing/v1alpha1/trigger_types.go index 63be349e13d..c83873698bd 100644 --- a/pkg/apis/eventing/v1alpha1/trigger_types.go +++ b/pkg/apis/eventing/v1alpha1/trigger_types.go @@ -67,7 +67,7 @@ type TriggerSpec struct { } type TriggerFilter struct { - ExactMatch TriggerFilterAttributes `json:"exactMatch,omitempty"` + ExactMatch *TriggerFilterAttributes `json:"exactMatch,omitempty"` } type TriggerFilterAttributes struct { @@ -106,6 +106,9 @@ const ( TriggerConditionVirtualService duckv1alpha1.ConditionType = "VirtualService" TriggerConditionSubscribed duckv1alpha1.ConditionType = "Subscribed" + + // Constant to represent that we should allow anything. + TriggerAnyFilter = "Any" ) // GetCondition returns the condition currently associated with the given type, or nil. diff --git a/pkg/apis/eventing/v1alpha1/trigger_validation.go b/pkg/apis/eventing/v1alpha1/trigger_validation.go index fdf3a9ff08b..4a149dabea5 100644 --- a/pkg/apis/eventing/v1alpha1/trigger_validation.go +++ b/pkg/apis/eventing/v1alpha1/trigger_validation.go @@ -37,6 +37,11 @@ func (ts *TriggerSpec) Validate() *apis.FieldError { errs = errs.Also(fe) } + if ts.Filter.ExactMatch == nil { + fe := apis.ErrMissingField("filter.exactMatch") + errs = errs.Also(fe) + } + if isSubscriberSpecNilOrEmpty(ts.Subscriber) { fe := apis.ErrMissingField("subscriber") errs = errs.Also(fe) diff --git a/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go index 88e1c446671..89bd9d76f0b 100644 --- a/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go @@ -600,7 +600,15 @@ func (in *Trigger) DeepCopyObject() runtime.Object { // 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 - out.ExactMatch = in.ExactMatch + if in.ExactMatch != nil { + in, out := &in.ExactMatch, &out.ExactMatch + if *in == nil { + *out = nil + } else { + *out = new(TriggerFilterAttributes) + **out = **in + } + } return } @@ -672,7 +680,7 @@ func (in *TriggerSpec) DeepCopyInto(out *TriggerSpec) { *out = nil } else { *out = new(TriggerFilter) - **out = **in + (*in).DeepCopyInto(*out) } } if in.Subscriber != nil { diff --git a/pkg/broker/receiver.go b/pkg/broker/receiver.go index 4b4cfe89136..c6b6107b289 100644 --- a/pkg/broker/receiver.go +++ b/pkg/broker/receiver.go @@ -28,10 +28,6 @@ import ( "sigs.k8s.io/controller-runtime/pkg/manager" ) -const ( - Any = "" -) - // Receiver parses Cloud Events and sends them to the channel. type Receiver struct { logger *zap.Logger @@ -99,12 +95,12 @@ func (r *Receiver) getTrigger(ctx context.Context, ref provisioners.ChannelRefer func (r *Receiver) shouldSendMessage(ts *eventingv1alpha1.TriggerSpec, m *provisioners.Message) bool { filterType := ts.Filter.ExactMatch.Type - if filterType != Any && filterType != m.Headers["Ce-Eventtype"] { + if filterType != eventingv1alpha1.TriggerAnyFilter && filterType != m.Headers["Ce-Eventtype"] { r.logger.Debug("Wrong type", zap.String("trigger.spec.filter.exactMatch.type", filterType), zap.String("message.type", m.Headers["Ce-Eventtype"])) return false } filterSource := ts.Filter.ExactMatch.Source - if filterSource != Any && filterSource != m.Headers["Ce-Source"] { + if filterSource != eventingv1alpha1.TriggerAnyFilter && filterSource != m.Headers["Ce-Source"] { r.logger.Debug("Wrong source", zap.String("trigger.spec.filter.exactMatch.source", filterSource), zap.String("message.source", m.Headers["Ce-Source"])) return false } From e75141c81ec3182ca37e17b167bb91ea9b833f36 Mon Sep 17 00:00:00 2001 From: nachocano Date: Wed, 13 Feb 2019 13:38:03 -0800 Subject: [PATCH 049/221] Attempt to reconcile broker in trigger controller --- pkg/reconciler/v1alpha1/trigger/trigger.go | 110 +++++++++++++++++++-- 1 file changed, 101 insertions(+), 9 deletions(-) diff --git a/pkg/reconciler/v1alpha1/trigger/trigger.go b/pkg/reconciler/v1alpha1/trigger/trigger.go index 8c2d57b26d9..c61900d04f1 100644 --- a/pkg/reconciler/v1alpha1/trigger/trigger.go +++ b/pkg/reconciler/v1alpha1/trigger/trigger.go @@ -19,6 +19,10 @@ package trigger import ( "context" "fmt" + "sync" + + "github.com/knative/eventing/pkg/provisioners" + "k8s.io/apimachinery/pkg/runtime" "k8s.io/client-go/dynamic" @@ -56,8 +60,11 @@ const ( // itself when creating events. controllerAgentName = "trigger-controller" + finalizerName = controllerAgentName + // Name of the corev1.Events emitted from the reconciliation process triggerReconciled = "TriggerReconciled" + triggerReconcileFailed = "TriggerReconcileFailed" triggerUpdateStatusFailed = "TriggerUpdateStatusFailed" ) @@ -67,19 +74,23 @@ type reconciler struct { dynamicClient dynamic.Interface recorder record.EventRecorder + triggersLock sync.RWMutex + triggers map[string]map[reconcile.Request]bool + logger *zap.Logger } // Verify the struct implements reconcile.Reconciler var _ reconcile.Reconciler = &reconciler{} -// ProvideController returns a function that returns a Broker controller. +// ProvideController returns a function that returns a Trigger controller. func ProvideController(logger *zap.Logger) func(manager.Manager) (controller.Controller, error) { return func(mgr manager.Manager) (controller.Controller, error) { - // Setup a new controller to Reconcile Brokers. + // Setup a new controller to Reconcile Triggers. r := &reconciler{ recorder: mgr.GetRecorder(controllerAgentName), logger: logger, + triggers: make(map[string]map[reconcile.Request]bool), } c, err := controller.New(controllerAgentName, mgr, controller.Options{ Reconciler: r, @@ -94,14 +105,17 @@ func ProvideController(logger *zap.Logger) func(manager.Manager) (controller.Con } // Watch all the resources that the Trigger reconciles. - for _, t := range []runtime.Object{ &corev1.Service{}, &istiov1alpha3.VirtualService{}, &v1alpha1.Subscription{} } { - err = c.Watch(&source.Kind{Type: t}, &handler.EnqueueRequestForOwner{OwnerType: &v1alpha1.Broker{}, IsController: true}) + for _, t := range []runtime.Object{&corev1.Service{}, &istiov1alpha3.VirtualService{}, &v1alpha1.Subscription{}} { + err = c.Watch(&source.Kind{Type: t}, &handler.EnqueueRequestForOwner{OwnerType: &v1alpha1.Trigger{}, IsController: true}) if err != nil { return nil, err } } - // TODO reconcile after a Broker change. This might require keeping a map from Broker -> []Trigger. + if err = c.Watch(&source.Kind{Type: &v1alpha1.Channel{}}, &handler.EnqueueRequestsFromMapFunc{ToRequests: &mapAllTriggers{r}}); err != nil { + return nil, err + } + // TODO reconcile after a change to the subscriber. I'm not sure how this is possible, but we should do it if we // can find a way. @@ -109,6 +123,24 @@ func ProvideController(logger *zap.Logger) func(manager.Manager) (controller.Con } } +type mapAllTriggers struct { + r *reconciler +} + +func (m *mapAllTriggers) Map(o handler.MapObject) []reconcile.Request { + m.r.triggersLock.RLock() + defer m.r.triggersLock.RUnlock() + triggersInNamespace := m.r.triggers[o.Meta.GetNamespace()] + if triggersInNamespace == nil { + return []reconcile.Request{} + } + reqs := make([]reconcile.Request, 0, len(triggersInNamespace)) + for name := range triggersInNamespace { + reqs = append(reqs, name) + } + return reqs +} + func (r *reconciler) InjectClient(c client.Client) error { r.client = c return nil @@ -137,27 +169,31 @@ func (r *reconciler) Reconcile(request reconcile.Request) (reconcile.Result, err } if err != nil { - logging.FromContext(ctx).Error("Could not Get Trigger", zap.Error(err)) + logging.FromContext(ctx).Error("Could not get Trigger", zap.Error(err)) return reconcile.Result{}, err } + // Modify a copy, not the original. + trigger = trigger.DeepCopy() + // Reconcile this copy of the Trigger and then write back any status updates regardless of // whether the reconcile error out. reconcileErr := r.reconcile(ctx, trigger) if reconcileErr != nil { logging.FromContext(ctx).Error("Error reconciling Trigger", zap.Error(reconcileErr)) + r.recorder.Eventf(trigger, corev1.EventTypeWarning, triggerReconcileFailed, "Trigger reconciliation failed: %v", reconcileErr) } else { logging.FromContext(ctx).Debug("Trigger reconciled") - r.recorder.Event(trigger, corev1.EventTypeNormal, triggerReconciled, "Trigger reconciled") + r.recorder.Eventf(trigger, corev1.EventTypeNormal, triggerReconciled, "Trigger reconciled: %q", trigger.Name) } - if _, err = r.updateStatus(trigger.DeepCopy()); err != nil { + if _, err = r.updateStatus(trigger); err != nil { logging.FromContext(ctx).Error("Failed to update Trigger status", zap.Error(err)) r.recorder.Eventf(trigger, corev1.EventTypeWarning, triggerUpdateStatusFailed, "Failed to update Trigger's status: %v", err) return reconcile.Result{}, err } - // Requeue if the resource is not ready: + // Requeue if the resource is not ready return reconcile.Result{}, reconcileErr } @@ -172,9 +208,14 @@ func (r *reconciler) reconcile(ctx context.Context, t *v1alpha1.Trigger) error { if t.DeletionTimestamp != nil { // Everything is cleaned up by the garbage collector. + r.removeFromTriggers(t) + provisioners.RemoveFinalizer(t, finalizerName) return nil } + provisioners.AddFinalizer(t, finalizerName) + r.AddToTriggers(t) + b, err := r.getBroker(ctx, t) if err != nil { logging.FromContext(ctx).Error("Unable to get the Broker", zap.Error(err)) @@ -221,6 +262,57 @@ func (r *reconciler) reconcile(ctx context.Context, t *v1alpha1.Trigger) error { return nil } +func (r *reconciler) AddToTriggers(t *v1alpha1.Trigger) { + name := reconcile.Request{ + NamespacedName: types.NamespacedName{ + Namespace: t.Namespace, + Name: t.Name, + }, + } + + // We will be reconciling an already existing Trigger far more often than adding a new one, so + // check with a read lock before using the write lock. + r.triggersLock.RLock() + triggersInNamespace := r.triggers[t.Namespace] + var present bool + if triggersInNamespace != nil { + _, present = triggersInNamespace[name] + } else { + present = false + } + r.triggersLock.RUnlock() + + if present { + // Already present in the map. + return + } + + r.triggersLock.Lock() + triggersInNamespace = r.triggers[t.Namespace] + if triggersInNamespace == nil { + r.triggers[t.Namespace] = make(map[reconcile.Request]bool) + triggersInNamespace = r.triggers[t.Namespace] + } + triggersInNamespace[name] = false + r.triggersLock.Unlock() +} + +func (r *reconciler) removeFromTriggers(t *v1alpha1.Trigger) { + name := reconcile.Request{ + NamespacedName: types.NamespacedName{ + Namespace: t.Namespace, + Name: t.Name, + }, + } + + r.triggersLock.Lock() + triggersInNamespace := r.triggers[t.Namespace] + if triggersInNamespace != nil { + delete(triggersInNamespace, name) + } + r.triggersLock.Unlock() +} + // updateStatus may in fact update the trigger's finalizers in addition to the status func (r *reconciler) updateStatus(trigger *v1alpha1.Trigger) (*v1alpha1.Trigger, error) { objectKey := client.ObjectKey{Namespace: trigger.Namespace, Name: trigger.Name} From e79b8f70180ef3f90e9af4ce43bf2e95bc772adb Mon Sep 17 00:00:00 2001 From: Adam Harwayne Date: Tue, 12 Feb 2019 23:02:47 -0800 Subject: [PATCH 050/221] Broker controller unit tests. --- pkg/apis/eventing/v1alpha1/broker_types.go | 4 +- pkg/reconciler/v1alpha1/broker/broker.go | 34 +- pkg/reconciler/v1alpha1/broker/broker_test.go | 658 ++++++++++++++++++ .../v1alpha1/broker/resources/filter.go | 1 + .../v1alpha1/broker/resources/ingress.go | 5 +- .../v1alpha1/namespace/namespace_test.go | 2 +- 6 files changed, 682 insertions(+), 22 deletions(-) diff --git a/pkg/apis/eventing/v1alpha1/broker_types.go b/pkg/apis/eventing/v1alpha1/broker_types.go index b50cd43101a..6cad4d3efbd 100644 --- a/pkg/apis/eventing/v1alpha1/broker_types.go +++ b/pkg/apis/eventing/v1alpha1/broker_types.go @@ -139,9 +139,9 @@ func (bs *BrokerStatus) MarkFilterReady() { func (bs *BrokerStatus) SetAddress(hostname string) { bs.Address.Hostname = hostname if hostname != "" { - chanCondSet.Manage(bs).MarkTrue(BrokerConditionAddressable) + brokerCondSet.Manage(bs).MarkTrue(BrokerConditionAddressable) } else { - chanCondSet.Manage(bs).MarkFalse(BrokerConditionAddressable, "emptyHostname", "hostname is the empty string") + brokerCondSet.Manage(bs).MarkFalse(BrokerConditionAddressable, "emptyHostname", "hostname is the empty string") } } diff --git a/pkg/reconciler/v1alpha1/broker/broker.go b/pkg/reconciler/v1alpha1/broker/broker.go index 8a79adfd902..1e4c52b2735 100644 --- a/pkg/reconciler/v1alpha1/broker/broker.go +++ b/pkg/reconciler/v1alpha1/broker/broker.go @@ -20,6 +20,7 @@ import ( "context" "fmt" "k8s.io/apimachinery/pkg/runtime" + "time" "k8s.io/client-go/dynamic" "k8s.io/client-go/rest" @@ -106,7 +107,7 @@ func ProvideController(logger *zap.Logger, ingressImage, ingressServiceAccount, } // Watch all the resources that the Broker reconciles. - for _, t := range []runtime.Object{ &v1alpha1.Channel{}, &corev1.Service{}, &v1.Deployment{} } { + for _, t := range []runtime.Object{&v1alpha1.Channel{}, &corev1.Service{}, &v1.Deployment{}} { err = c.Watch(&source.Kind{Type: t}, &handler.EnqueueRequestForOwner{OwnerType: &v1alpha1.Broker{}, IsController: true}) if err != nil { return nil, err @@ -151,9 +152,11 @@ func (r *reconciler) Reconcile(request reconcile.Request) (reconcile.Result, err // Reconcile this copy of the Broker and then write back any status updates regardless of // whether the reconcile error out. - reconcileErr := r.reconcile(ctx, broker) + result, reconcileErr := r.reconcile(ctx, broker) if reconcileErr != nil { logging.FromContext(ctx).Error("Error reconciling Broker", zap.Error(reconcileErr)) + } else if result.Requeue || result.RequeueAfter > 0 { + logging.FromContext(ctx).Debug("Broker reconcile requeuing") } else { logging.FromContext(ctx).Debug("Broker reconciled") r.recorder.Event(broker, corev1.EventTypeNormal, brokerReconciled, "Broker reconciled") @@ -166,10 +169,10 @@ func (r *reconciler) Reconcile(request reconcile.Request) (reconcile.Result, err } // Requeue if the resource is not ready: - return reconcile.Result{}, reconcileErr + return result, reconcileErr } -func (r *reconciler) reconcile(ctx context.Context, b *v1alpha1.Broker) error { +func (r *reconciler) reconcile(ctx context.Context, b *v1alpha1.Broker) (reconcile.Result, error) { b.Status.InitializeConditions() // 1. Channel is created for all events. @@ -179,48 +182,48 @@ func (r *reconciler) reconcile(ctx context.Context, b *v1alpha1.Broker) error { if b.DeletionTimestamp != nil { // Everything is cleaned up by the garbage collector. - return nil + return reconcile.Result{}, nil } c, err := r.reconcileChannel(ctx, b) if err != nil { logging.FromContext(ctx).Error("Problem reconciling the channel", zap.Error(err)) b.Status.MarkChannelFailed(err) - return err + return reconcile.Result{}, err } else if c.Status.Address.Hostname == "" { logging.FromContext(ctx).Info("Channel is not yet ready", zap.Any("c", c)) - // TODO Just re-enqueue, don't return an error - return nil + // Give the Channel some time to get its address. One second was chosen arbitrarily. + return reconcile.Result{RequeueAfter: time.Second}, nil } b.Status.MarkChannelReady() _, err = r.reconcileFilterDeployment(ctx, b) if err != nil { logging.FromContext(ctx).Error("Problem reconciling filter deployment", zap.Error(err)) - return err + return reconcile.Result{}, err } _, err = r.reconcileFilterService(ctx, b) if err != nil { logging.FromContext(ctx).Error("Problem reconciling filter service", zap.Error(err)) - return err + return reconcile.Result{}, err } b.Status.MarkFilterReady() _, err = r.reconcileIngressDeployment(ctx, b, c) if err != nil { logging.FromContext(ctx).Error("Problem reconciling ingress deployment", zap.Error(err)) - return err + return reconcile.Result{}, err } svc, err := r.reconcileIngressService(ctx, b) if err != nil { logging.FromContext(ctx).Error("Problem reconciling ingress Service", zap.Error(err)) - return err + return reconcile.Result{}, err } b.Status.MarkIngressReady() b.Status.SetAddress(names.ServiceHostName(svc.Name, svc.Namespace)) - return nil + return reconcile.Result{}, nil } // updateStatus may in fact update the broker's finalizers in addition to the status @@ -420,15 +423,12 @@ func (r *reconciler) reconcileService(ctx context.Context, svc *corev1.Service) } func (r *reconciler) reconcileIngressDeployment(ctx context.Context, b *v1alpha1.Broker, c *v1alpha1.Channel) (*v1.Deployment, error) { - expected, err := resources.MakeIngress(&resources.IngressArgs{ + expected := resources.MakeIngress(&resources.IngressArgs{ Broker: b, Image: r.ingressImage, ServiceAccountName: r.ingressServiceAccountName, ChannelAddress: c.Status.Address.Hostname, }) - if err != nil { - return nil, err - } return r.reconcileDeployment(ctx, expected) } diff --git a/pkg/reconciler/v1alpha1/broker/broker_test.go b/pkg/reconciler/v1alpha1/broker/broker_test.go index 7a887c44284..992bbe5708e 100644 --- a/pkg/reconciler/v1alpha1/broker/broker_test.go +++ b/pkg/reconciler/v1alpha1/broker/broker_test.go @@ -17,13 +17,60 @@ limitations under the License. package broker import ( + "context" + "errors" + "fmt" "github.com/google/go-cmp/cmp" + "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" + controllertesting "github.com/knative/eventing/pkg/reconciler/testing" + "github.com/knative/eventing/pkg/reconciler/v1alpha1/broker/resources" + duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" + "go.uber.org/zap" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" "k8s.io/client-go/dynamic" + "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/rest" + "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + "strings" "testing" + "time" ) +const ( + testNS = "test-namespace" + brokerName = "test-broker" + channelHostname = "foo.bar.svc.cluster.local" + + filterImage = "filter-image" + filterSA = "filter-SA" + ingressImage = "ingress-image" + ingressSA = "ingress-SA" +) + +var ( + trueVal = true + + channelProvisioner = &corev1.ObjectReference{ + APIVersion: "eventing.knative.dev/v1alpha1", + Kind: "ClusterChannelProvisioner", + Name: "my-provisioner", + } + + // deletionTime is used when objects are marked as deleted. Rfc3339Copy() + // truncates to seconds to match the loss of precision during serialization. + deletionTime = metav1.Now().Rfc3339Copy() +) + +func init() { + // Add types to scheme + v1alpha1.AddToScheme(scheme.Scheme) +} + func TestProvideController(t *testing.T) { //TODO(grantr) This needs a mock of manager.Manager. Creating a manager // with a fake Config fails because the Manager tries to contact the @@ -89,3 +136,614 @@ func TestInjectConfig(t *testing.T) { t.Errorf("Unexpected dynamicClient type. Expected: %T, Got: %T", wantDynClient, r.dynamicClient) } } + +func TestReconcile(t *testing.T) { + testCases := []controllertesting.TestCase{ + { + Name: "Broker not found", + }, + { + Name: "Broker.Get fails", + Scheme: scheme.Scheme, + Mocks: controllertesting.Mocks{ + MockGets: []controllertesting.MockGet{ + func(_ client.Client, _ context.Context, _ client.ObjectKey, obj runtime.Object) (controllertesting.MockHandled, error) { + if _, ok := obj.(*v1alpha1.Broker); ok { + return controllertesting.Handled, errors.New("test error getting the Broker") + } + return controllertesting.Unhandled, nil + }, + }, + }, + WantErrMsg: "test error getting the Broker", + }, + { + Name: "Broker is being deleted", + Scheme: scheme.Scheme, + InitialState: []runtime.Object{ + makeDeletingBroker(), + }, + WantEvent: []corev1.Event{ + { + Reason: brokerReconciled, Type: corev1.EventTypeNormal, + }, + }, + }, + { + Name: "Channel.List error", + Scheme: scheme.Scheme, + InitialState: []runtime.Object{ + makeBroker(), + }, + Mocks: controllertesting.Mocks{ + MockLists: []controllertesting.MockList{ + func(_ client.Client, _ context.Context, _ *client.ListOptions, list runtime.Object) (controllertesting.MockHandled, error) { + if _, ok := list.(*v1alpha1.ChannelList); ok { + return controllertesting.Handled, errors.New("test error listing channels") + } + return controllertesting.Unhandled, nil + }, + }, + }, + WantErrMsg: "test error listing channels", + }, + { + Name: "Channel.Create error", + Scheme: scheme.Scheme, + InitialState: []runtime.Object{ + makeBroker(), + }, + Mocks: controllertesting.Mocks{ + MockCreates: []controllertesting.MockCreate{ + func(_ client.Client, _ context.Context, obj runtime.Object) (controllertesting.MockHandled, error) { + if _, ok := obj.(*v1alpha1.Channel); ok { + return controllertesting.Handled, errors.New("test error creating Channel") + } + return controllertesting.Unhandled, nil + }, + }, + }, + WantErrMsg: "test error creating Channel", + }, + { + Name: "Channel is different than expected", + Scheme: scheme.Scheme, + InitialState: []runtime.Object{ + makeBroker(), + makeDifferentChannel(), + }, + WantPresent: []runtime.Object{ + // This is special because the Channel is not updated, unlike most things that + // differ from expected. + // TODO uncomment the following line once our test framework supports searching for + // GenerateName. + //makeDifferentChannel(), + }, + WantEvent: []corev1.Event{ + { + Reason: brokerReconciled, Type: corev1.EventTypeNormal, + }, + }, + }, + { + Name: "Channel is not yet Addressable", + Scheme: scheme.Scheme, + InitialState: []runtime.Object{ + makeBroker(), + makeNonAddressableChannel(), + }, + WantResult: reconcile.Result{RequeueAfter: time.Second}, + }, + { + Name: "Filter Deployment.Get error", + Scheme: scheme.Scheme, + InitialState: []runtime.Object{ + makeBroker(), + makeChannel(), + }, + Mocks: controllertesting.Mocks{ + MockGets: []controllertesting.MockGet{ + func(_ client.Client, _ context.Context, key client.ObjectKey, obj runtime.Object) (controllertesting.MockHandled, error) { + if _, ok := obj.(*appsv1.Deployment); ok { + if strings.Contains(key.Name, "filter") { + return controllertesting.Handled, errors.New("test error getting filter Deployment") + } + } + return controllertesting.Unhandled, nil + }, + }, + }, + WantErrMsg: "test error getting filter Deployment", + }, + { + Name: "Filter Deployment.Create error", + Scheme: scheme.Scheme, + InitialState: []runtime.Object{ + makeBroker(), + makeChannel(), + }, + Mocks: controllertesting.Mocks{ + MockCreates: []controllertesting.MockCreate{ + func(_ client.Client, _ context.Context, obj runtime.Object) (controllertesting.MockHandled, error) { + if d, ok := obj.(*appsv1.Deployment); ok { + if d.Labels["eventing.knative.dev/brokerRole"] == "filter" { + return controllertesting.Handled, errors.New("test error creating filter Deployment") + } + } + return controllertesting.Unhandled, nil + }, + }, + }, + WantErrMsg: "test error creating filter Deployment", + }, + { + Name: "Filter Deployment.Update error", + Scheme: scheme.Scheme, + InitialState: []runtime.Object{ + makeBroker(), + makeChannel(), + makeDifferentFilterDeployment(), + }, + Mocks: controllertesting.Mocks{ + MockUpdates: []controllertesting.MockUpdate{ + func(_ client.Client, _ context.Context, obj runtime.Object) (controllertesting.MockHandled, error) { + if d, ok := obj.(*appsv1.Deployment); ok { + if d.Labels["eventing.knative.dev/brokerRole"] == "filter" { + return controllertesting.Handled, errors.New("test error updating filter Deployment") + } + } + return controllertesting.Unhandled, nil + }, + }, + }, + WantErrMsg: "test error updating filter Deployment", + }, + { + Name: "Filter Service.Get error", + Scheme: scheme.Scheme, + InitialState: []runtime.Object{ + makeBroker(), + makeChannel(), + }, + Mocks: controllertesting.Mocks{ + MockGets: []controllertesting.MockGet{ + func(_ client.Client, _ context.Context, key client.ObjectKey, obj runtime.Object) (controllertesting.MockHandled, error) { + if _, ok := obj.(*corev1.Service); ok { + if strings.Contains(key.Name, "filter") { + return controllertesting.Handled, errors.New("test error getting filter Service") + } + } + return controllertesting.Unhandled, nil + }, + }, + }, + WantErrMsg: "test error getting filter Service", + }, + { + Name: "Filter Service.Create error", + Scheme: scheme.Scheme, + InitialState: []runtime.Object{ + makeBroker(), + makeChannel(), + }, + Mocks: controllertesting.Mocks{ + MockCreates: []controllertesting.MockCreate{ + func(_ client.Client, _ context.Context, obj runtime.Object) (controllertesting.MockHandled, error) { + if svc, ok := obj.(*corev1.Service); ok { + if svc.Labels["eventing.knative.dev/brokerRole"] == "filter" { + return controllertesting.Handled, errors.New("test error creating filter Service") + } + } + return controllertesting.Unhandled, nil + }, + }, + }, + WantErrMsg: "test error creating filter Service", + }, + { + Name: "Filter Service.Update error", + Scheme: scheme.Scheme, + InitialState: []runtime.Object{ + makeBroker(), + makeChannel(), + makeDifferentFilterService(), + }, + Mocks: controllertesting.Mocks{ + MockUpdates: []controllertesting.MockUpdate{ + func(_ client.Client, _ context.Context, obj runtime.Object) (controllertesting.MockHandled, error) { + if svc, ok := obj.(*corev1.Service); ok { + if svc.Labels["eventing.knative.dev/brokerRole"] == "filter" { + return controllertesting.Handled, errors.New("test error updating filter Service") + } + } + return controllertesting.Unhandled, nil + }, + }, + }, + WantErrMsg: "test error updating filter Service", + }, + { + Name: "Ingress Deployment.Get error", + Scheme: scheme.Scheme, + InitialState: []runtime.Object{ + makeBroker(), + makeChannel(), + }, + Mocks: controllertesting.Mocks{ + MockGets: []controllertesting.MockGet{ + func(_ client.Client, _ context.Context, key client.ObjectKey, obj runtime.Object) (controllertesting.MockHandled, error) { + if _, ok := obj.(*appsv1.Deployment); ok { + if strings.Contains(key.Name, "ingress") { + return controllertesting.Handled, errors.New("test error getting ingress Deployment") + } + } + return controllertesting.Unhandled, nil + }, + }, + }, + WantErrMsg: "test error getting ingress Deployment", + }, + { + Name: "Ingress Deployment.Create error", + Scheme: scheme.Scheme, + InitialState: []runtime.Object{ + makeBroker(), + makeChannel(), + }, + Mocks: controllertesting.Mocks{ + MockCreates: []controllertesting.MockCreate{ + func(_ client.Client, _ context.Context, obj runtime.Object) (controllertesting.MockHandled, error) { + if d, ok := obj.(*appsv1.Deployment); ok { + if d.Labels["eventing.knative.dev/brokerRole"] == "ingress" { + return controllertesting.Handled, errors.New("test error creating ingress Deployment") + } + } + return controllertesting.Unhandled, nil + }, + }, + }, + WantErrMsg: "test error creating ingress Deployment", + }, + { + Name: "Ingress Deployment.Update error", + Scheme: scheme.Scheme, + InitialState: []runtime.Object{ + makeBroker(), + makeChannel(), + makeDifferentIngressDeployment(), + }, + Mocks: controllertesting.Mocks{ + MockUpdates: []controllertesting.MockUpdate{ + func(_ client.Client, _ context.Context, obj runtime.Object) (controllertesting.MockHandled, error) { + if d, ok := obj.(*appsv1.Deployment); ok { + if d.Labels["eventing.knative.dev/brokerRole"] == "ingress" { + return controllertesting.Handled, errors.New("test error updating ingress Deployment") + } + } + return controllertesting.Unhandled, nil + }, + }, + }, + WantErrMsg: "test error updating ingress Deployment", + }, + { + Name: "Ingress Service.Get error", + Scheme: scheme.Scheme, + InitialState: []runtime.Object{ + makeBroker(), + makeChannel(), + }, + Mocks: controllertesting.Mocks{ + MockGets: []controllertesting.MockGet{ + func(_ client.Client, _ context.Context, key client.ObjectKey, obj runtime.Object) (controllertesting.MockHandled, error) { + if _, ok := obj.(*corev1.Service); ok { + if key.Name == fmt.Sprintf("%s-broker", brokerName) { + return controllertesting.Handled, errors.New("test error getting ingress Service") + } + } + return controllertesting.Unhandled, nil + }, + }, + }, + WantErrMsg: "test error getting ingress Service", + }, + { + Name: "Ingress Service.Create error", + Scheme: scheme.Scheme, + InitialState: []runtime.Object{ + makeBroker(), + makeChannel(), + }, + Mocks: controllertesting.Mocks{ + MockCreates: []controllertesting.MockCreate{ + func(_ client.Client, _ context.Context, obj runtime.Object) (controllertesting.MockHandled, error) { + if svc, ok := obj.(*corev1.Service); ok { + if svc.Labels["eventing.knative.dev/brokerRole"] == "ingress" { + return controllertesting.Handled, errors.New("test error creating ingress Service") + } + } + return controllertesting.Unhandled, nil + }, + }, + }, + WantErrMsg: "test error creating ingress Service", + }, + { + Name: "Ingress Service.Update error", + Scheme: scheme.Scheme, + InitialState: []runtime.Object{ + makeBroker(), + makeChannel(), + makeDifferentIngressService(), + }, + Mocks: controllertesting.Mocks{ + MockUpdates: []controllertesting.MockUpdate{ + func(_ client.Client, _ context.Context, obj runtime.Object) (controllertesting.MockHandled, error) { + if svc, ok := obj.(*corev1.Service); ok { + if svc.Labels["eventing.knative.dev/brokerRole"] == "ingress" { + return controllertesting.Handled, errors.New("test error updating ingress Service") + } + } + return controllertesting.Unhandled, nil + }, + }, + }, + WantErrMsg: "test error updating ingress Service", + }, + { + Name: "Broker.Get for status update fails", + Scheme: scheme.Scheme, + InitialState: []runtime.Object{ + makeBroker(), + makeChannel(), + }, + Mocks: controllertesting.Mocks{ + MockGets: []controllertesting.MockGet{ + // The first Get works. + func(innerClient client.Client, ctx context.Context, key client.ObjectKey, obj runtime.Object) (controllertesting.MockHandled, error) { + if _, ok := obj.(*v1alpha1.Broker); ok { + return controllertesting.Handled, innerClient.Get(ctx, key, obj) + } + return controllertesting.Unhandled, nil + }, + // The second Get fails. + func(_ client.Client, _ context.Context, _ client.ObjectKey, obj runtime.Object) (controllertesting.MockHandled, error) { + if _, ok := obj.(*v1alpha1.Broker); ok { + return controllertesting.Handled, errors.New("test error getting the Broker for status update") + } + return controllertesting.Unhandled, nil + }, + }, + }, + WantErrMsg: "test error getting the Broker for status update", + WantEvent: []corev1.Event{ + { + Reason: brokerReconciled, Type: corev1.EventTypeNormal, + }, + { + Reason: brokerUpdateStatusFailed, Type: corev1.EventTypeWarning, + }, + }, + }, + { + Name: "Broker.Status.Update error", + Scheme: scheme.Scheme, + InitialState: []runtime.Object{ + makeBroker(), + makeChannel(), + }, + Mocks: controllertesting.Mocks{ + MockStatusUpdates: []controllertesting.MockStatusUpdate{ + func(_ client.Client, _ context.Context, obj runtime.Object) (controllertesting.MockHandled, error) { + if _, ok := obj.(*v1alpha1.Broker); ok { + return controllertesting.Handled, errors.New("test error updating the Broker status") + } + return controllertesting.Unhandled, nil + }, + }, + }, + WantErrMsg: "test error updating the Broker status", + WantEvent: []corev1.Event{ + { + Reason: brokerReconciled, Type: corev1.EventTypeNormal, + }, + { + Reason: brokerUpdateStatusFailed, Type: corev1.EventTypeWarning, + }, + }, + }, + { + Name: "Successful reconcile", + Scheme: scheme.Scheme, + InitialState: []runtime.Object{ + makeBroker(), + // The Channel needs to be addressable for the reconcile to succeed. + makeChannel(), + }, + WantPresent: []runtime.Object{ + makeReadyBroker(), + // TODO Uncomment makeChannel() when our test framework handles generateName. + //makeChannel(), + makeFilterDeployment(), + makeFilterService(), + makeIngressDeployment(), + makeIngressService(), + }, + WantEvent: []corev1.Event{ + { + Reason: brokerReconciled, Type: corev1.EventTypeNormal, + }, + }, + }, + } + for _, tc := range testCases { + c := tc.GetClient() + dc := tc.GetDynamicClient() + recorder := tc.GetEventRecorder() + + r := &reconciler{ + client: c, + dynamicClient: dc, + restConfig: &rest.Config{}, + recorder: recorder, + logger: zap.NewNop(), + + filterImage: filterImage, + filterServiceAccountName: filterSA, + ingressImage: ingressImage, + ingressServiceAccountName: ingressSA, + } + tc.ReconcileKey = fmt.Sprintf("%s/%s", testNS, brokerName) + tc.IgnoreTimes = true + t.Run(tc.Name, tc.Runner(t, r, c, recorder)) + } +} + +func makeBroker() *v1alpha1.Broker { + return &v1alpha1.Broker{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "eventing.knative.dev/v1alpha1", + Kind: "Broker", + }, + ObjectMeta: metav1.ObjectMeta{ + Namespace: testNS, + Name: brokerName, + }, + Spec: v1alpha1.BrokerSpec{ + ChannelTemplate: &v1alpha1.ChannelSpec{ + Provisioner: channelProvisioner, + }, + }, + } +} + +func makeReadyBroker() *v1alpha1.Broker { + b := makeBroker() + b.Status.InitializeConditions() + b.Status.MarkChannelReady() + b.Status.SetAddress(fmt.Sprintf("%s-broker.%s.svc.cluster.local", brokerName, testNS)) + b.Status.MarkFilterReady() + b.Status.MarkIngressReady() + return b +} + +func makeDeletingBroker() *v1alpha1.Broker { + b := makeReadyBroker() + b.DeletionTimestamp = &deletionTime + return b +} + +func makeChannel() *v1alpha1.Channel { + return &v1alpha1.Channel{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: testNS, + GenerateName: fmt.Sprintf("%s-broker-", brokerName), + Labels: map[string]string{ + "eventing.knative.dev/broker": brokerName, + "eventing.knative.dev/brokerEverything": "true", + }, + OwnerReferences: []metav1.OwnerReference{ + getOwnerReference(), + }, + }, + Spec: v1alpha1.ChannelSpec{ + Provisioner: channelProvisioner, + }, + Status: v1alpha1.ChannelStatus{ + Address: duckv1alpha1.Addressable{ + Hostname: channelHostname, + }, + }, + } +} + +func makeNonAddressableChannel() *v1alpha1.Channel { + c := makeChannel() + c.Status.Address = duckv1alpha1.Addressable{} + return c +} + +func makeDifferentChannel() *v1alpha1.Channel { + c := makeChannel() + c.Spec.Provisioner.Name = "some-other-provisioner" + return c +} + +func makeFilterDeployment() *appsv1.Deployment { + d := resources.MakeFilterDeployment(&resources.FilterArgs{ + Broker: makeBroker(), + Image: filterImage, + ServiceAccountName: filterSA, + }) + d.TypeMeta = metav1.TypeMeta{ + APIVersion: "apps/v1", + Kind: "Deployment", + } + return d +} + +func makeDifferentFilterDeployment() *appsv1.Deployment { + d := makeFilterDeployment() + d.Spec.Template.Spec.Containers[0].Image = "some-other-image" + return d +} + +func makeFilterService() *corev1.Service { + svc := resources.MakeFilterService(makeBroker()) + svc.TypeMeta = metav1.TypeMeta{ + APIVersion: "v1", + Kind: "Service", + } + return svc +} + +func makeDifferentFilterService() *corev1.Service { + s := makeFilterService() + s.Spec.Selector["eventing.knative.dev/broker"] = "some-other-value" + return s +} + +func makeIngressDeployment() *appsv1.Deployment { + d := resources.MakeIngress(&resources.IngressArgs{ + Broker: makeBroker(), + Image: ingressImage, + ServiceAccountName: ingressSA, + ChannelAddress: channelHostname, + }) + d.TypeMeta = metav1.TypeMeta{ + APIVersion: "apps/v1", + Kind: "Deployment", + } + return d +} + +func makeDifferentIngressDeployment() *appsv1.Deployment { + d := makeIngressDeployment() + d.Spec.Template.Spec.Containers[0].Image = "some-other-image" + return d +} + +func makeIngressService() *corev1.Service { + svc := resources.MakeIngressService(makeBroker()) + svc.TypeMeta = metav1.TypeMeta{ + APIVersion: "v1", + Kind: "Service", + } + return svc +} + +func makeDifferentIngressService() *corev1.Service { + s := makeIngressService() + s.Spec.Selector["eventing.knative.dev/broker"] = "some-other-value" + return s +} + +func getOwnerReference() metav1.OwnerReference { + return metav1.OwnerReference{ + APIVersion: v1alpha1.SchemeGroupVersion.String(), + Kind: "Broker", + Name: brokerName, + Controller: &trueVal, + BlockOwnerDeletion: &trueVal, + } +} diff --git a/pkg/reconciler/v1alpha1/broker/resources/filter.go b/pkg/reconciler/v1alpha1/broker/resources/filter.go index 38d049f068e..428d0e4a38e 100644 --- a/pkg/reconciler/v1alpha1/broker/resources/filter.go +++ b/pkg/reconciler/v1alpha1/broker/resources/filter.go @@ -46,6 +46,7 @@ func MakeFilterDeployment(args *FilterArgs) *appsv1.Deployment { Kind: "Broker", }), }, + Labels: filterLabels(args.Broker), }, Spec: appsv1.DeploymentSpec{ Selector: &metav1.LabelSelector{ diff --git a/pkg/reconciler/v1alpha1/broker/resources/ingress.go b/pkg/reconciler/v1alpha1/broker/resources/ingress.go index a5444b5cf68..406f1b85daa 100644 --- a/pkg/reconciler/v1alpha1/broker/resources/ingress.go +++ b/pkg/reconciler/v1alpha1/broker/resources/ingress.go @@ -35,7 +35,7 @@ type IngressArgs struct { ChannelAddress string } -func MakeIngress(args *IngressArgs) (*appsv1.Deployment, error) { +func MakeIngress(args *IngressArgs) *appsv1.Deployment { return &appsv1.Deployment{ ObjectMeta: metav1.ObjectMeta{ Namespace: args.Broker.Namespace, @@ -47,6 +47,7 @@ func MakeIngress(args *IngressArgs) (*appsv1.Deployment, error) { Kind: "Broker", }), }, + Labels: ingressLabels(args.Broker), }, Spec: appsv1.DeploymentSpec{ Selector: &metav1.LabelSelector{ @@ -80,7 +81,7 @@ func MakeIngress(args *IngressArgs) (*appsv1.Deployment, error) { }, }, }, - }, nil + } } func MakeIngressService(b *eventingv1alpha1.Broker) *corev1.Service { diff --git a/pkg/reconciler/v1alpha1/namespace/namespace_test.go b/pkg/reconciler/v1alpha1/namespace/namespace_test.go index cdf1876ac29..a3ce6a05615 100644 --- a/pkg/reconciler/v1alpha1/namespace/namespace_test.go +++ b/pkg/reconciler/v1alpha1/namespace/namespace_test.go @@ -150,7 +150,7 @@ func TestReconcile(t *testing.T) { Name: "Namespace not found", }, { - Name: "Namespace get fails", + Name: "Namespace.Get fails", Scheme: scheme.Scheme, Mocks: controllertesting.Mocks{ MockGets: []controllertesting.MockGet{ From 30f1c7478c8ec7680b6f9259f6d45ab45f78db25 Mon Sep 17 00:00:00 2001 From: nachocano Date: Wed, 13 Feb 2019 16:15:47 -0800 Subject: [PATCH 051/221] Deleting and re-creating subscription object as the backing channel spec is immutable. --- pkg/reconciler/v1alpha1/trigger/trigger.go | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/pkg/reconciler/v1alpha1/trigger/trigger.go b/pkg/reconciler/v1alpha1/trigger/trigger.go index c61900d04f1..17159cf0776 100644 --- a/pkg/reconciler/v1alpha1/trigger/trigger.go +++ b/pkg/reconciler/v1alpha1/trigger/trigger.go @@ -112,7 +112,7 @@ func ProvideController(logger *zap.Logger) func(manager.Manager) (controller.Con } } - if err = c.Watch(&source.Kind{Type: &v1alpha1.Channel{}}, &handler.EnqueueRequestsFromMapFunc{ToRequests: &mapAllTriggers{r}}); err != nil { + if err = c.Watch(&source.Kind{Type: &v1alpha1.Broker{}}, &handler.EnqueueRequestsFromMapFunc{ToRequests: &mapAllTriggers{r}}); err != nil { return nil, err } @@ -595,9 +595,17 @@ func (r *reconciler) subscribeToBrokerChannel(ctx context.Context, t *v1alpha1.T // Update Subscription if it has changed. Ignore the generation. expected.Spec.DeprecatedGeneration = sub.Spec.DeprecatedGeneration if !equality.Semantic.DeepDerivative(expected.Spec, sub.Spec) { - sub.Spec = expected.Spec - err = r.client.Update(ctx, sub) + // Given that the backing channel spec is immutable, we cannot just update the subscription. + // We delete it instead, and re-create it. + err = r.client.Delete(ctx, sub) if err != nil { + logging.FromContext(ctx).Info("Cannot delete subscription", zap.Error(err)) + return nil, err + } + sub = expected + err = r.client.Create(ctx, sub) + if err != nil { + logging.FromContext(ctx).Info("Cannot create subscription", zap.Error(err)) return nil, err } } From e45d19a9e5cd78fc0fa3484b17959d415fc34cf3 Mon Sep 17 00:00:00 2001 From: nachocano Date: Wed, 13 Feb 2019 16:27:15 -0800 Subject: [PATCH 052/221] Adding comment --- pkg/reconciler/v1alpha1/trigger/trigger.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/reconciler/v1alpha1/trigger/trigger.go b/pkg/reconciler/v1alpha1/trigger/trigger.go index 17159cf0776..6258ca7195d 100644 --- a/pkg/reconciler/v1alpha1/trigger/trigger.go +++ b/pkg/reconciler/v1alpha1/trigger/trigger.go @@ -112,6 +112,7 @@ func ProvideController(logger *zap.Logger) func(manager.Manager) (controller.Con } } + // Watch for Broker changes. if err = c.Watch(&source.Kind{Type: &v1alpha1.Broker{}}, &handler.EnqueueRequestsFromMapFunc{ToRequests: &mapAllTriggers{r}}); err != nil { return nil, err } From 1628333455022889ccd03701a2a930185632dfd6 Mon Sep 17 00:00:00 2001 From: Adam Harwayne Date: Wed, 13 Feb 2019 17:13:13 -0800 Subject: [PATCH 053/221] Rename Trigger.Spec.Filter.ExactMatch to Trigger.Spec.Filter.SourceAndType. Add unit tests for the filter binary. --- .../eventing/v1alpha1/trigger_defaults.go | 2 +- pkg/apis/eventing/v1alpha1/trigger_types.go | 4 +- .../eventing/v1alpha1/trigger_validation.go | 2 +- .../v1alpha1/zz_generated.deepcopy.go | 14 +- pkg/broker/receiver.go | 8 +- pkg/broker/receiver_test.go | 168 +++++++++++------- t2.yaml | 2 +- 7 files changed, 117 insertions(+), 83 deletions(-) diff --git a/pkg/apis/eventing/v1alpha1/trigger_defaults.go b/pkg/apis/eventing/v1alpha1/trigger_defaults.go index e3dd6c32818..b95ce930497 100644 --- a/pkg/apis/eventing/v1alpha1/trigger_defaults.go +++ b/pkg/apis/eventing/v1alpha1/trigger_defaults.go @@ -26,6 +26,6 @@ func (ts *TriggerSpec) SetDefaults() { } // Make a default filter that allows anything. if ts.Filter == nil { - ts.Filter = &TriggerFilter{&TriggerFilterAttributes{Type: TriggerAnyFilter, Source: TriggerAnyFilter}} + ts.Filter = &TriggerFilter{&TriggerFilterSourceAndType{Type: TriggerAnyFilter, Source: TriggerAnyFilter}} } } diff --git a/pkg/apis/eventing/v1alpha1/trigger_types.go b/pkg/apis/eventing/v1alpha1/trigger_types.go index c83873698bd..794a91b4dc3 100644 --- a/pkg/apis/eventing/v1alpha1/trigger_types.go +++ b/pkg/apis/eventing/v1alpha1/trigger_types.go @@ -67,10 +67,10 @@ type TriggerSpec struct { } type TriggerFilter struct { - ExactMatch *TriggerFilterAttributes `json:"exactMatch,omitempty"` + SourceAndType *TriggerFilterSourceAndType `json:"sourceAndType,omitempty"` } -type TriggerFilterAttributes struct { +type TriggerFilterSourceAndType struct { Type string `json:"type,omitempty"` Source string `json:"source,omitempty"` } diff --git a/pkg/apis/eventing/v1alpha1/trigger_validation.go b/pkg/apis/eventing/v1alpha1/trigger_validation.go index 4a149dabea5..3aca17c6581 100644 --- a/pkg/apis/eventing/v1alpha1/trigger_validation.go +++ b/pkg/apis/eventing/v1alpha1/trigger_validation.go @@ -37,7 +37,7 @@ func (ts *TriggerSpec) Validate() *apis.FieldError { errs = errs.Also(fe) } - if ts.Filter.ExactMatch == nil { + if ts.Filter.SourceAndType == nil { fe := apis.ErrMissingField("filter.exactMatch") errs = errs.Also(fe) } diff --git a/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go index 89bd9d76f0b..44ba2ee9196 100644 --- a/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go @@ -600,12 +600,12 @@ func (in *Trigger) DeepCopyObject() runtime.Object { // 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.ExactMatch != nil { - in, out := &in.ExactMatch, &out.ExactMatch + if in.SourceAndType != nil { + in, out := &in.SourceAndType, &out.SourceAndType if *in == nil { *out = nil } else { - *out = new(TriggerFilterAttributes) + *out = new(TriggerFilterSourceAndType) **out = **in } } @@ -623,17 +623,17 @@ func (in *TriggerFilter) DeepCopy() *TriggerFilter { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *TriggerFilterAttributes) DeepCopyInto(out *TriggerFilterAttributes) { +func (in *TriggerFilterSourceAndType) DeepCopyInto(out *TriggerFilterSourceAndType) { *out = *in return } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TriggerFilterAttributes. -func (in *TriggerFilterAttributes) DeepCopy() *TriggerFilterAttributes { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TriggerFilterSourceAndType. +func (in *TriggerFilterSourceAndType) DeepCopy() *TriggerFilterSourceAndType { if in == nil { return nil } - out := new(TriggerFilterAttributes) + out := new(TriggerFilterSourceAndType) in.DeepCopyInto(out) return out } diff --git a/pkg/broker/receiver.go b/pkg/broker/receiver.go index c6b6107b289..d51c3d6c755 100644 --- a/pkg/broker/receiver.go +++ b/pkg/broker/receiver.go @@ -94,12 +94,16 @@ func (r *Receiver) getTrigger(ctx context.Context, ref provisioners.ChannelRefer } func (r *Receiver) shouldSendMessage(ts *eventingv1alpha1.TriggerSpec, m *provisioners.Message) bool { - filterType := ts.Filter.ExactMatch.Type + if ts.Filter == nil || ts.Filter.SourceAndType == nil { + r.logger.Error("No filter specified") + return false + } + filterType := ts.Filter.SourceAndType.Type if filterType != eventingv1alpha1.TriggerAnyFilter && filterType != m.Headers["Ce-Eventtype"] { r.logger.Debug("Wrong type", zap.String("trigger.spec.filter.exactMatch.type", filterType), zap.String("message.type", m.Headers["Ce-Eventtype"])) return false } - filterSource := ts.Filter.ExactMatch.Source + filterSource := ts.Filter.SourceAndType.Source if filterSource != eventingv1alpha1.TriggerAnyFilter && filterSource != m.Headers["Ce-Source"] { r.logger.Debug("Wrong source", zap.String("trigger.spec.filter.exactMatch.source", filterSource), zap.String("message.source", m.Headers["Ce-Source"])) return false diff --git a/pkg/broker/receiver_test.go b/pkg/broker/receiver_test.go index aa553399351..d841d895f6b 100644 --- a/pkg/broker/receiver_test.go +++ b/pkg/broker/receiver_test.go @@ -17,13 +17,14 @@ package broker import ( - "context" + "errors" + "fmt" + "github.com/knative/eventing/pkg/provisioners" + "net/http" "net/http/httptest" "strings" "testing" - "github.com/knative/eventing/contrib/gcppubsub/pkg/util" - eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" "k8s.io/client-go/kubernetes/scheme" @@ -33,24 +34,13 @@ import ( "k8s.io/apimachinery/pkg/runtime" "sigs.k8s.io/controller-runtime/pkg/client/fake" - - "github.com/knative/eventing/contrib/gcppubsub/pkg/util/testcreds" ) const ( - validMessage = `{ - "cloudEventsVersion" : "0.1", - "eventType" : "com.example.someevent", - "eventTypeVersion" : "1.0", - "source" : "/mycontext", - "eventID" : "A234-1234-1234", - "eventTime" : "2018-04-05T17:31:00Z", - "extensions" : { - "comExampleExtension" : "value" - }, - "contentType" : "text/xml", - "data" : "" -}` + testNS = "test-namespace" + triggerName = "test-trigger" + eventType = `"com.example.someevent"` + eventSource = `"/mycontext"` ) func init() { @@ -60,49 +50,55 @@ func init() { func TestReceiver(t *testing.T) { testCases := map[string]struct { - initialState []runtime.Object - expectedErr bool + initialState []runtime.Object + dispatchErr error + expectedErr bool + expectedDispatch bool }{ - "can't get channel": { + "Trigger.Get fails": { + // No trigger exists, so the Get will fail. + expectedErr: true, + }, + "Trigger doesn't have SubscriberURI": { initialState: []runtime.Object{ - testcreds.MakeSecretWithInvalidCreds(), + makeTriggerWithoutSubscriberURI(), }, expectedErr: true, }, - "can't read status": { + "Trigger without a Filter": { initialState: []runtime.Object{ - testcreds.MakeSecretWithInvalidCreds(), - makeChannelWithBadStatus(), + makeTriggerWithoutFilter(), }, - expectedErr: true, }, - "blank status": { + "Wrong type": { initialState: []runtime.Object{ - testcreds.MakeSecretWithInvalidCreds(), - makeChannelWithBlankStatus(), + makeTrigger("some-other-type", "Any"), }, - expectedErr: true, }, - "credential fails": { + "Wrong source": { initialState: []runtime.Object{ - testcreds.MakeSecretWithInvalidCreds(), - makeChannel(), + makeTrigger("Any", "some-other-source"), }, - expectedErr: true, }, - "PubSub client fails": { + "Dispatch failed": { initialState: []runtime.Object{ - testcreds.MakeSecretWithCreds(), - makeChannel(), + makeTrigger("Any", "Any"), }, - expectedErr: true, + dispatchErr: errors.New("test error dispatching"), + expectedErr: true, + expectedDispatch: true, }, - "Publish fails": { + "Dispatch succeeded - Any": { initialState: []runtime.Object{ - testcreds.MakeSecretWithCreds(), - makeChannel(), + makeTrigger("Any", "Any"), }, - expectedErr: true, + expectedDispatch: true, + }, + "Dispatch succeeded - Specific": { + initialState: []runtime.Object{ + makeTrigger(eventType, eventSource), + }, + expectedDispatch: true, }, } for n, tc := range testCases { @@ -110,10 +106,13 @@ func TestReceiver(t *testing.T) { mr, _ := New( zap.NewNop(), fake.NewFakeClient(tc.initialState...)) + fd := &fakeDispatcher{ + err: tc.dispatchErr, + } + mr.dispatcher = fd + resp := httptest.NewRecorder() - req := httptest.NewRequest("POST", "/", strings.NewReader(validMessage)) - req.Host = "test-trigger.test-namespace.triggers.cluster.local" - mr.newMessageReceiver().HandleRequest(resp, req) + mr.newMessageReceiver().HandleRequest(resp, makeRequest()) if tc.expectedErr { if resp.Result().StatusCode >= 200 && resp.Result().StatusCode < 300 { t.Errorf("Expected an error. Actual: %v", resp.Result()) @@ -123,43 +122,74 @@ func TestReceiver(t *testing.T) { t.Errorf("Expected success. Actual: %v", resp.Result()) } } + if tc.expectedDispatch != fd.requestReceived { + t.Errorf("Incorrect dispatch. Expected %v, Actual %v", tc.expectedDispatch, fd.requestReceived) + } }) } } -func makeChannel() *eventingv1alpha1.Channel { - c := &eventingv1alpha1.Channel{ +type fakeDispatcher struct { + err error + requestReceived bool +} + +func (d *fakeDispatcher) DispatchMessage(_ *provisioners.Message, _, _ string, _ provisioners.DispatchDefaults) error { + d.requestReceived = true + return d.err +} + +func makeTrigger(t, s string) *eventingv1alpha1.Trigger { + return &eventingv1alpha1.Trigger{ TypeMeta: v1.TypeMeta{ APIVersion: "eventing.knative.dev/v1alpha1", - Kind: "Channel", + Kind: "Trigger", }, ObjectMeta: v1.ObjectMeta{ - Namespace: "test-namespace", - Name: "test-channel", + Namespace: testNS, + Name: triggerName, + }, + Spec: eventingv1alpha1.TriggerSpec{ + Filter: &eventingv1alpha1.TriggerFilter{ + SourceAndType: &eventingv1alpha1.TriggerFilterSourceAndType{ + Type: t, + Source: s, + }, + }, + }, + Status: eventingv1alpha1.TriggerStatus{ + SubscriberURI: "subscriberURI", }, } - pcs := &util.GcpPubSubChannelStatus{ - GCPProject: "project", - Secret: testcreds.Secret, - SecretKey: testcreds.SecretKey, - } - if err := util.SetInternalStatus(context.Background(), c, pcs); err != nil { - panic(err) - } - return c } -func makeChannelWithBlankStatus() *eventingv1alpha1.Channel { - c := makeChannel() - c.Status = eventingv1alpha1.ChannelStatus{} - return c +func makeTriggerWithoutFilter() *eventingv1alpha1.Trigger { + t := makeTrigger("Any", "Any") + t.Spec.Filter = nil + return t } -func makeChannelWithBadStatus() *eventingv1alpha1.Channel { - c := makeChannel() - c.Status.Internal = &runtime.RawExtension{ - // SecretKey must be a string, not an integer, so this will fail during json.Unmarshal. - Raw: []byte(`{"secretKey": 123}`), +func makeTriggerWithoutSubscriberURI() *eventingv1alpha1.Trigger { + t := makeTrigger("Any", "Any") + t.Status = eventingv1alpha1.TriggerStatus{} + return t +} + +func makeRequest() *http.Request { + req := httptest.NewRequest("POST", "/", strings.NewReader(``)) + req.Host = fmt.Sprintf("%s.%s.triggers.cluster.local", triggerName, testNS) + + eventAttributes := map[string]string{ + "CE-CloudEventsVersion": `"0.1"`, + "CE-EventType": eventType, + "CE-EventTypeVersion": `"1.0"`, + "CE-Source": eventSource, + "CE-EventID": `"A234-1234-1234"`, + "CE-EventTime": `"2018-04-05T17:31:00Z"`, + "contentType": "text/xml", + } + for k, v := range eventAttributes { + req.Header.Set(k, v) } - return c + return req } diff --git a/t2.yaml b/t2.yaml index 6274a6166b4..105b912796e 100644 --- a/t2.yaml +++ b/t2.yaml @@ -6,7 +6,7 @@ spec: # Our Cloud Event parsing library seems to have a bug and forces to put type and source in double # quotes (as it thinks the actual value is `"foo"`, not `foo`). filter: - exactMatch: + sourceAndType: type: '"com.example.someevent"' source: '"/mycontext/subcontext"' subscriber: From cbbd06615687a6012261e4ecaadef702a7dd5649 Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Wed, 13 Feb 2019 23:18:46 -0800 Subject: [PATCH 054/221] Adding event messages --- pkg/apis/eventing/v1alpha1/trigger_validation.go | 2 +- pkg/reconciler/v1alpha1/trigger/trigger.go | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/pkg/apis/eventing/v1alpha1/trigger_validation.go b/pkg/apis/eventing/v1alpha1/trigger_validation.go index 3aca17c6581..073784972b1 100644 --- a/pkg/apis/eventing/v1alpha1/trigger_validation.go +++ b/pkg/apis/eventing/v1alpha1/trigger_validation.go @@ -38,7 +38,7 @@ func (ts *TriggerSpec) Validate() *apis.FieldError { } if ts.Filter.SourceAndType == nil { - fe := apis.ErrMissingField("filter.exactMatch") + fe := apis.ErrMissingField("filter.sourceAndType") errs = errs.Also(fe) } diff --git a/pkg/reconciler/v1alpha1/trigger/trigger.go b/pkg/reconciler/v1alpha1/trigger/trigger.go index 6258ca7195d..b86d694a525 100644 --- a/pkg/reconciler/v1alpha1/trigger/trigger.go +++ b/pkg/reconciler/v1alpha1/trigger/trigger.go @@ -66,6 +66,8 @@ const ( triggerReconciled = "TriggerReconciled" triggerReconcileFailed = "TriggerReconcileFailed" triggerUpdateStatusFailed = "TriggerUpdateStatusFailed" + subscriptionDeleteFailed = "SubscriptionDeleteFailed" + subscriptionCreateFailed = "SubscriptionCreateFailed" ) type reconciler struct { @@ -601,12 +603,14 @@ func (r *reconciler) subscribeToBrokerChannel(ctx context.Context, t *v1alpha1.T err = r.client.Delete(ctx, sub) if err != nil { logging.FromContext(ctx).Info("Cannot delete subscription", zap.Error(err)) + r.recorder.Eventf(t, corev1.EventTypeWarning, subscriptionDeleteFailed, "Delete Trigger's subscription failed: %v", err) return nil, err } sub = expected err = r.client.Create(ctx, sub) if err != nil { logging.FromContext(ctx).Info("Cannot create subscription", zap.Error(err)) + r.recorder.Eventf(t, corev1.EventTypeWarning, subscriptionCreateFailed, "Create Trigger's subscription failed: %v", err) return nil, err } } From c33c5691e7c0dde9447d391408689b5ef9d320ba Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Wed, 13 Feb 2019 23:52:47 -0800 Subject: [PATCH 055/221] Using the broker's namespacedNamed as key to the triggers map. With this we allow to reconcile only the triggers that belong to the particular broker that changed --- pkg/reconciler/v1alpha1/trigger/trigger.go | 48 ++++++++++++++-------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/pkg/reconciler/v1alpha1/trigger/trigger.go b/pkg/reconciler/v1alpha1/trigger/trigger.go index b86d694a525..b7c3252c3df 100644 --- a/pkg/reconciler/v1alpha1/trigger/trigger.go +++ b/pkg/reconciler/v1alpha1/trigger/trigger.go @@ -70,6 +70,8 @@ const ( subscriptionCreateFailed = "SubscriptionCreateFailed" ) +var dummyValue struct{} + type reconciler struct { client client.Client restConfig *rest.Config @@ -77,7 +79,10 @@ type reconciler struct { recorder record.EventRecorder triggersLock sync.RWMutex - triggers map[string]map[reconcile.Request]bool + // Contains the triggers that correspond to a particular broker. + // We use this to reconcile only the triggers that correspond to a certain broker. + // brokerNamespacedName -> triggerReconcileRequest -> dummy struct + triggers map[types.NamespacedName]map[reconcile.Request]struct{} logger *zap.Logger } @@ -92,7 +97,7 @@ func ProvideController(logger *zap.Logger) func(manager.Manager) (controller.Con r := &reconciler{ recorder: mgr.GetRecorder(controllerAgentName), logger: logger, - triggers: make(map[string]map[reconcile.Request]bool), + triggers: make(map[types.NamespacedName]map[reconcile.Request]struct{}), } c, err := controller.New(controllerAgentName, mgr, controller.Options{ Reconciler: r, @@ -133,12 +138,13 @@ type mapAllTriggers struct { func (m *mapAllTriggers) Map(o handler.MapObject) []reconcile.Request { m.r.triggersLock.RLock() defer m.r.triggersLock.RUnlock() - triggersInNamespace := m.r.triggers[o.Meta.GetNamespace()] - if triggersInNamespace == nil { + brokerNamespacedName := types.NamespacedName{Namespace: o.Meta.GetNamespace(), Name: o.Meta.GetName()} + triggersInBrokerNamespacedName := m.r.triggers[brokerNamespacedName] + if triggersInBrokerNamespacedName == nil { return []reconcile.Request{} } - reqs := make([]reconcile.Request, 0, len(triggersInNamespace)) - for name := range triggersInNamespace { + reqs := make([]reconcile.Request, 0, len(triggersInBrokerNamespacedName)) + for name := range triggersInBrokerNamespacedName { reqs = append(reqs, name) } return reqs @@ -273,13 +279,17 @@ func (r *reconciler) AddToTriggers(t *v1alpha1.Trigger) { }, } + brokerNamespacedName := types.NamespacedName{ + Namespace: t.Namespace, + Name: t.Spec.Broker} + // We will be reconciling an already existing Trigger far more often than adding a new one, so // check with a read lock before using the write lock. r.triggersLock.RLock() - triggersInNamespace := r.triggers[t.Namespace] + triggersInBrokerNamespacedName := r.triggers[brokerNamespacedName] var present bool - if triggersInNamespace != nil { - _, present = triggersInNamespace[name] + if triggersInBrokerNamespacedName != nil { + _, present = triggersInBrokerNamespacedName[name] } else { present = false } @@ -291,12 +301,12 @@ func (r *reconciler) AddToTriggers(t *v1alpha1.Trigger) { } r.triggersLock.Lock() - triggersInNamespace = r.triggers[t.Namespace] - if triggersInNamespace == nil { - r.triggers[t.Namespace] = make(map[reconcile.Request]bool) - triggersInNamespace = r.triggers[t.Namespace] + triggersInBrokerNamespacedName = r.triggers[brokerNamespacedName] + if triggersInBrokerNamespacedName == nil { + r.triggers[brokerNamespacedName] = make(map[reconcile.Request]struct{}) + triggersInBrokerNamespacedName = r.triggers[brokerNamespacedName] } - triggersInNamespace[name] = false + triggersInBrokerNamespacedName[name] = dummyValue r.triggersLock.Unlock() } @@ -308,10 +318,14 @@ func (r *reconciler) removeFromTriggers(t *v1alpha1.Trigger) { }, } + brokerNamespacedName := types.NamespacedName{ + Namespace: t.Namespace, + Name: t.Spec.Broker} + r.triggersLock.Lock() - triggersInNamespace := r.triggers[t.Namespace] - if triggersInNamespace != nil { - delete(triggersInNamespace, name) + triggersInBrokerNamespacedName := r.triggers[brokerNamespacedName] + if triggersInBrokerNamespacedName != nil { + delete(triggersInBrokerNamespacedName, name) } r.triggersLock.Unlock() } From 40ca8da7bf7d9a02c4bcba32e566d75124d6518d Mon Sep 17 00:00:00 2001 From: nachocano Date: Thu, 14 Feb 2019 14:44:18 -0800 Subject: [PATCH 056/221] Adding some tests to trigger --- pkg/reconciler/v1alpha1/trigger/trigger.go | 2 +- .../v1alpha1/trigger/trigger_test.go | 364 +++++++++++++++++- 2 files changed, 364 insertions(+), 2 deletions(-) diff --git a/pkg/reconciler/v1alpha1/trigger/trigger.go b/pkg/reconciler/v1alpha1/trigger/trigger.go index b7c3252c3df..42404fed7fa 100644 --- a/pkg/reconciler/v1alpha1/trigger/trigger.go +++ b/pkg/reconciler/v1alpha1/trigger/trigger.go @@ -193,7 +193,7 @@ func (r *reconciler) Reconcile(request reconcile.Request) (reconcile.Result, err r.recorder.Eventf(trigger, corev1.EventTypeWarning, triggerReconcileFailed, "Trigger reconciliation failed: %v", reconcileErr) } else { logging.FromContext(ctx).Debug("Trigger reconciled") - r.recorder.Eventf(trigger, corev1.EventTypeNormal, triggerReconciled, "Trigger reconciled: %q", trigger.Name) + r.recorder.Event(trigger, corev1.EventTypeNormal, triggerReconciled, "Trigger reconciled") } if _, err = r.updateStatus(trigger); err != nil { diff --git a/pkg/reconciler/v1alpha1/trigger/trigger_test.go b/pkg/reconciler/v1alpha1/trigger/trigger_test.go index 298a3a48f5c..454875e81a1 100644 --- a/pkg/reconciler/v1alpha1/trigger/trigger_test.go +++ b/pkg/reconciler/v1alpha1/trigger/trigger_test.go @@ -17,13 +17,67 @@ limitations under the License. package trigger import ( + "context" + "errors" + "fmt" + "testing" + + "k8s.io/apimachinery/pkg/runtime/schema" + + "sigs.k8s.io/controller-runtime/pkg/client" + + "k8s.io/apimachinery/pkg/util/intstr" + + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + "github.com/google/go-cmp/cmp" + "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" + controllertesting "github.com/knative/eventing/pkg/reconciler/testing" + duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" + "go.uber.org/zap" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/dynamic" + "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/rest" "sigs.k8s.io/controller-runtime/pkg/client/fake" - "testing" ) +const ( + testNS = "test-namespace" + triggerName = "test-trigger" + brokerName = "test-broker" + + subscriberAPIVersion = "v1" + subscriberKind = "Service" + subscriberName = "subscriberName" + + channelHostname = "foo.bar.svc.cluster.local" + + k8sServiceName = "k8sServiceName" +) + +var ( + trueVal = true + // deletionTime is used when objects are marked as deleted. Rfc3339Copy() + // truncates to seconds to match the loss of precision during serialization. + deletionTime = metav1.Now().Rfc3339Copy() + + // Map of events to set test cases' expectations easier. + events = map[string]corev1.Event{ + triggerReconciled: {Reason: triggerReconciled, Type: corev1.EventTypeNormal}, + triggerUpdateStatusFailed: {Reason: triggerUpdateStatusFailed, Type: corev1.EventTypeWarning}, + triggerReconcileFailed: {Reason: triggerReconcileFailed, Type: corev1.EventTypeWarning}, + } +) + +func init() { + // Add types to scheme + v1alpha1.AddToScheme(scheme.Scheme) +} + func TestProvideController(t *testing.T) { //TODO(grantr) This needs a mock of manager.Manager. Creating a manager // with a fake Config fails because the Manager tries to contact the @@ -89,3 +143,311 @@ func TestInjectConfig(t *testing.T) { t.Errorf("Unexpected dynamicClient type. Expected: %T, Got: %T", wantDynClient, r.dynamicClient) } } + +func TestReconcile(t *testing.T) { + testCases := []controllertesting.TestCase{ + { + Name: "Trigger not found", + }, + { + Name: "Get Trigger error", + Scheme: scheme.Scheme, + Mocks: controllertesting.Mocks{ + MockGets: []controllertesting.MockGet{ + func(_ client.Client, _ context.Context, _ client.ObjectKey, obj runtime.Object) (controllertesting.MockHandled, error) { + if _, ok := obj.(*v1alpha1.Trigger); ok { + return controllertesting.Handled, errors.New("test error getting the Trigger") + } + return controllertesting.Unhandled, nil + }, + }, + }, + WantErrMsg: "test error getting the Trigger", + }, + { + Name: "Trigger being deleted", + Scheme: scheme.Scheme, + InitialState: []runtime.Object{ + makeDeletingTrigger(), + }, + WantEvent: []corev1.Event{events[triggerReconciled]}, + }, + { + Name: "Get Broker error", + Scheme: scheme.Scheme, + InitialState: []runtime.Object{ + makeTrigger(), + }, + Mocks: controllertesting.Mocks{ + MockGets: []controllertesting.MockGet{ + func(_ client.Client, _ context.Context, _ client.ObjectKey, obj runtime.Object) (controllertesting.MockHandled, error) { + if _, ok := obj.(*v1alpha1.Broker); ok { + return controllertesting.Handled, errors.New("test error getting broker") + } + return controllertesting.Unhandled, nil + }, + }, + }, + WantErrMsg: "test error getting broker", + WantEvent: []corev1.Event{events[triggerReconcileFailed]}, + }, + { + Name: "Get Broker channel error", + Scheme: scheme.Scheme, + InitialState: []runtime.Object{ + makeTrigger(), + makeBroker(), + }, + Mocks: controllertesting.Mocks{ + MockLists: []controllertesting.MockList{ + func(_ client.Client, _ context.Context, _ *client.ListOptions, list runtime.Object) (controllertesting.MockHandled, error) { + if _, ok := list.(*v1alpha1.ChannelList); ok { + return controllertesting.Handled, errors.New("test error getting broker's channel") + } + return controllertesting.Unhandled, nil + }, + }, + }, + WantErrMsg: "test error getting broker's channel", + WantEvent: []corev1.Event{events[triggerReconcileFailed]}, + }, + { + Name: "Resolve subscriberURI error", + Scheme: scheme.Scheme, + InitialState: []runtime.Object{ + makeTrigger(), + makeBroker(), + makeChannel(), + }, + Mocks: controllertesting.Mocks{ + MockGets: []controllertesting.MockGet{ + func(_ client.Client, _ context.Context, key client.ObjectKey, obj runtime.Object) (controllertesting.MockHandled, error) { + if _, ok := obj.(*corev1.Service); ok { + return controllertesting.Handled, errors.New("test error resolving subscriber URI") + } + return controllertesting.Unhandled, nil + }, + }, + }, + WantErrMsg: "test error resolving subscriber URI", + WantEvent: []corev1.Event{events[triggerReconcileFailed]}, + }, + { + Name: "Create K8s Service error", + Scheme: scheme.Scheme, + InitialState: []runtime.Object{ + makeTrigger(), + makeBroker(), + makeChannel(), + makeSubscriberService(), + }, + Mocks: controllertesting.Mocks{ + MockCreates: []controllertesting.MockCreate{ + func(_ client.Client, _ context.Context, obj runtime.Object) (controllertesting.MockHandled, error) { + if _, ok := obj.(*corev1.Service); ok { + return controllertesting.Handled, errors.New("test error creating k8s service") + } + return controllertesting.Unhandled, nil + }, + }, + }, + WantErrMsg: "test error creating k8s service", + WantEvent: []corev1.Event{events[triggerReconcileFailed]}, + }, + { + Name: "Update K8s Service error", + Scheme: scheme.Scheme, + InitialState: []runtime.Object{ + makeTrigger(), + makeBroker(), + makeChannel(), + makeSubscriberService(), + makeK8sService(), + }, + Mocks: controllertesting.Mocks{ + MockUpdates: []controllertesting.MockUpdate{ + func(_ client.Client, _ context.Context, obj runtime.Object) (controllertesting.MockHandled, error) { + if _, ok := obj.(*corev1.Service); ok { + return controllertesting.Handled, errors.New("test error updating k8s service") + } + return controllertesting.Unhandled, nil + }, + }, + }, + WantErrMsg: "test error updating k8s service", + WantEvent: []corev1.Event{events[triggerReconcileFailed]}, + }, + } + for _, tc := range testCases { + c := tc.GetClient() + dc := tc.GetDynamicClient() + recorder := tc.GetEventRecorder() + + r := &reconciler{ + client: c, + dynamicClient: dc, + restConfig: &rest.Config{}, + recorder: recorder, + logger: zap.NewNop(), + triggers: make(map[types.NamespacedName]map[reconcile.Request]struct{}), + } + tc.ReconcileKey = fmt.Sprintf("%s/%s", testNS, triggerName) + tc.IgnoreTimes = true + t.Run(tc.Name, tc.Runner(t, r, c, recorder)) + } +} + +func makeTrigger() *v1alpha1.Trigger { + return &v1alpha1.Trigger{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "eventing.knative.dev/v1alpha1", + Kind: "Trigger", + }, + ObjectMeta: metav1.ObjectMeta{ + Namespace: testNS, + Name: triggerName, + }, + Spec: v1alpha1.TriggerSpec{ + Broker: brokerName, + Filter: &v1alpha1.TriggerFilter{ + SourceAndType: &v1alpha1.TriggerFilterSourceAndType{ + Source: "Any", + Type: "Any", + }, + }, + Subscriber: &v1alpha1.SubscriberSpec{ + Ref: &corev1.ObjectReference{ + Name: subscriberName, + Kind: subscriberKind, + APIVersion: subscriberAPIVersion, + }, + }, + }, + } +} + +func makeReadyTrigger() *v1alpha1.Trigger { + t := makeTrigger() + t.Status.InitializeConditions() + t.Status.MarkBrokerExists() + t.Status.SubscriberURI = fmt.Sprintf("%s-trigger.%s.svc.cluster.local", triggerName, testNS) + t.Status.MarkKubernetesServiceExists() + t.Status.MarkVirtualServiceExists() + t.Status.MarkSubscribed() + return t +} + +func makeDeletingTrigger() *v1alpha1.Trigger { + b := makeReadyTrigger() + b.DeletionTimestamp = &deletionTime + return b +} + +func makeBroker() *v1alpha1.Broker { + return &v1alpha1.Broker{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "eventing.knative.dev/v1alpha1", + Kind: "Broker", + }, + ObjectMeta: metav1.ObjectMeta{ + Namespace: testNS, + Name: brokerName, + }, + Spec: v1alpha1.BrokerSpec{ + ChannelTemplate: &v1alpha1.ChannelSpec{ + Provisioner: makeChannelProvisioner(), + }, + }, + } +} + +func makeChannelProvisioner() *corev1.ObjectReference { + return &corev1.ObjectReference{ + APIVersion: "eventing.knative.dev/v1alpha1", + Kind: "ClusterChannelProvisioner", + Name: "my-provisioner", + } +} + +func makeChannel() *v1alpha1.Channel { + return &v1alpha1.Channel{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: testNS, + GenerateName: fmt.Sprintf("%s-broker-", brokerName), + Labels: map[string]string{ + "eventing.knative.dev/broker": brokerName, + "eventing.knative.dev/brokerEverything": "true", + }, + OwnerReferences: []metav1.OwnerReference{ + getOwnerReference(), + }, + }, + Spec: v1alpha1.ChannelSpec{ + Provisioner: makeChannelProvisioner(), + }, + Status: v1alpha1.ChannelStatus{ + Address: duckv1alpha1.Addressable{ + Hostname: channelHostname, + }, + }, + } +} + +func makeSubscriberService() *corev1.Service { + return &corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: testNS, + Name: subscriberName, + }, + Spec: corev1.ServiceSpec{ + Ports: []corev1.ServicePort{ + { + Name: "http", + Port: 80, + TargetPort: intstr.FromInt(8080), + }, + }, + }, + } +} + +func makeK8sService() *corev1.Service { + return &corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: testNS, + Name: k8sServiceName, + Labels: map[string]string{ + "eventing.knative.dev/trigger": triggerName, + }, + OwnerReferences: []metav1.OwnerReference{ + *metav1.NewControllerRef(makeTrigger(), schema.GroupVersionKind{ + Group: v1alpha1.SchemeGroupVersion.Group, + Version: v1alpha1.SchemeGroupVersion.Version, + Kind: "Trigger", + }), + }, + }, + Spec: corev1.ServiceSpec{ + Selector: map[string]string{ + "eventing.knative.dev/trigger": triggerName, + }, + Ports: []corev1.ServicePort{ + { + Name: "http", + Port: 80, + TargetPort: intstr.FromInt(8080), + }, + }, + }, + } +} + +func getOwnerReference() metav1.OwnerReference { + return metav1.OwnerReference{ + APIVersion: v1alpha1.SchemeGroupVersion.String(), + Kind: "Broker", + Name: brokerName, + Controller: &trueVal, + BlockOwnerDeletion: &trueVal, + } +} From 650ef475f3b8c29db19fb290cf996d78ca3e422f Mon Sep 17 00:00:00 2001 From: nachocano Date: Thu, 14 Feb 2019 16:22:52 -0800 Subject: [PATCH 057/221] More UTs --- .../v1alpha1/trigger/trigger_test.go | 105 ++++++++++++------ 1 file changed, 74 insertions(+), 31 deletions(-) diff --git a/pkg/reconciler/v1alpha1/trigger/trigger_test.go b/pkg/reconciler/v1alpha1/trigger/trigger_test.go index 454875e81a1..9b873d3c479 100644 --- a/pkg/reconciler/v1alpha1/trigger/trigger_test.go +++ b/pkg/reconciler/v1alpha1/trigger/trigger_test.go @@ -22,13 +22,13 @@ import ( "fmt" "testing" - "k8s.io/apimachinery/pkg/runtime/schema" + "github.com/knative/eventing/pkg/reconciler/names" + "k8s.io/apimachinery/pkg/runtime" "sigs.k8s.io/controller-runtime/pkg/client" "k8s.io/apimachinery/pkg/util/intstr" - "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/reconcile" @@ -36,6 +36,7 @@ import ( "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" controllertesting "github.com/knative/eventing/pkg/reconciler/testing" duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" + istiov1alpha3 "github.com/knative/pkg/apis/istio/v1alpha3" "go.uber.org/zap" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -55,8 +56,6 @@ const ( subscriberName = "subscriberName" channelHostname = "foo.bar.svc.cluster.local" - - k8sServiceName = "k8sServiceName" ) var ( @@ -76,6 +75,7 @@ var ( func init() { // Add types to scheme v1alpha1.AddToScheme(scheme.Scheme) + istiov1alpha3.AddToScheme(scheme.Scheme) } func TestProvideController(t *testing.T) { @@ -262,7 +262,7 @@ func TestReconcile(t *testing.T) { makeBroker(), makeChannel(), makeSubscriberService(), - makeK8sService(), + makeDifferentK8sService(), }, Mocks: controllertesting.Mocks{ MockUpdates: []controllertesting.MockUpdate{ @@ -277,6 +277,53 @@ func TestReconcile(t *testing.T) { WantErrMsg: "test error updating k8s service", WantEvent: []corev1.Event{events[triggerReconcileFailed]}, }, + { + Name: "Create Virtual Service error", + Scheme: scheme.Scheme, + InitialState: []runtime.Object{ + makeTrigger(), + makeBroker(), + makeChannel(), + makeSubscriberService(), + makeK8sService(), + }, + Mocks: controllertesting.Mocks{ + MockCreates: []controllertesting.MockCreate{ + func(_ client.Client, _ context.Context, obj runtime.Object) (controllertesting.MockHandled, error) { + if _, ok := obj.(*istiov1alpha3.VirtualService); ok { + return controllertesting.Handled, errors.New("test error creating virtual service") + } + return controllertesting.Unhandled, nil + }, + }, + }, + WantErrMsg: "test error creating virtual service", + WantEvent: []corev1.Event{events[triggerReconcileFailed]}, + }, + { + Name: "Update Virtual Service error", + Scheme: scheme.Scheme, + InitialState: []runtime.Object{ + makeTrigger(), + makeBroker(), + makeChannel(), + makeSubscriberService(), + makeK8sService(), + makeDifferentVirtualService(), + }, + Mocks: controllertesting.Mocks{ + MockUpdates: []controllertesting.MockUpdate{ + func(_ client.Client, _ context.Context, obj runtime.Object) (controllertesting.MockHandled, error) { + if _, ok := obj.(*istiov1alpha3.VirtualService); ok { + return controllertesting.Handled, errors.New("test error updating virtual service") + } + return controllertesting.Unhandled, nil + }, + }, + }, + WantErrMsg: "test error updating virtual service", + WantEvent: []corev1.Event{events[triggerReconcileFailed]}, + }, } for _, tc := range testCases { c := tc.GetClient() @@ -412,34 +459,30 @@ func makeSubscriberService() *corev1.Service { } func makeK8sService() *corev1.Service { - return &corev1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: testNS, - Name: k8sServiceName, - Labels: map[string]string{ - "eventing.knative.dev/trigger": triggerName, - }, - OwnerReferences: []metav1.OwnerReference{ - *metav1.NewControllerRef(makeTrigger(), schema.GroupVersionKind{ - Group: v1alpha1.SchemeGroupVersion.Group, - Version: v1alpha1.SchemeGroupVersion.Version, - Kind: "Trigger", - }), - }, - }, - Spec: corev1.ServiceSpec{ - Selector: map[string]string{ - "eventing.knative.dev/trigger": triggerName, - }, - Ports: []corev1.ServicePort{ - { - Name: "http", - Port: 80, - TargetPort: intstr.FromInt(8080), - }, - }, + return newK8sService(makeTrigger()) +} + +func makeDifferentK8sService() *corev1.Service { + svc := makeK8sService() + svc.Spec.Ports = []corev1.ServicePort{ + { + Name: "http", + Port: 9999, }, } + return svc +} + +func makeVirtualService() *istiov1alpha3.VirtualService { + return newVirtualService(makeTrigger(), makeK8sService()) +} + +func makeDifferentVirtualService() *istiov1alpha3.VirtualService { + vsvc := makeVirtualService() + vsvc.Spec.Hosts = []string{ + names.ServiceHostName("other_svc_name", "other_svc_namespace"), + } + return vsvc } func getOwnerReference() metav1.OwnerReference { From d2c1ef8495c8aa041277f64ce1359815913b63ee Mon Sep 17 00:00:00 2001 From: nachocano Date: Thu, 14 Feb 2019 17:45:25 -0800 Subject: [PATCH 058/221] More UTs --- .../v1alpha1/trigger/trigger_test.go | 75 +++++++++++++++++-- 1 file changed, 69 insertions(+), 6 deletions(-) diff --git a/pkg/reconciler/v1alpha1/trigger/trigger_test.go b/pkg/reconciler/v1alpha1/trigger/trigger_test.go index 9b873d3c479..c5c6a59b1fc 100644 --- a/pkg/reconciler/v1alpha1/trigger/trigger_test.go +++ b/pkg/reconciler/v1alpha1/trigger/trigger_test.go @@ -25,11 +25,10 @@ import ( "github.com/knative/eventing/pkg/reconciler/names" "k8s.io/apimachinery/pkg/runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/reconcile" "github.com/google/go-cmp/cmp" @@ -55,7 +54,8 @@ const ( subscriberKind = "Service" subscriberName = "subscriberName" - channelHostname = "foo.bar.svc.cluster.local" + channelHostname = "foo.bar.svc.cluster.local" + channelProvisioner = "my-channel-provisioner" ) var ( @@ -69,6 +69,8 @@ var ( triggerReconciled: {Reason: triggerReconciled, Type: corev1.EventTypeNormal}, triggerUpdateStatusFailed: {Reason: triggerUpdateStatusFailed, Type: corev1.EventTypeWarning}, triggerReconcileFailed: {Reason: triggerReconcileFailed, Type: corev1.EventTypeWarning}, + subscriptionDeleteFailed: {Reason: subscriptionDeleteFailed, Type: corev1.EventTypeWarning}, + subscriptionCreateFailed: {Reason: subscriptionCreateFailed, Type: corev1.EventTypeWarning}, } ) @@ -324,6 +326,55 @@ func TestReconcile(t *testing.T) { WantErrMsg: "test error updating virtual service", WantEvent: []corev1.Event{events[triggerReconcileFailed]}, }, + { + Name: "Create Subscription error", + Scheme: scheme.Scheme, + InitialState: []runtime.Object{ + makeTrigger(), + makeBroker(), + makeChannel(), + makeSubscriberService(), + makeK8sService(), + makeVirtualService(), + }, + Mocks: controllertesting.Mocks{ + MockCreates: []controllertesting.MockCreate{ + func(_ client.Client, _ context.Context, obj runtime.Object) (controllertesting.MockHandled, error) { + if _, ok := obj.(*v1alpha1.Subscription); ok { + return controllertesting.Handled, errors.New("test error creating subscription") + } + return controllertesting.Unhandled, nil + }, + }, + }, + WantErrMsg: "test error creating subscription", + WantEvent: []corev1.Event{events[triggerReconcileFailed]}, + }, + { + Name: "Delete Subscription error", + Scheme: scheme.Scheme, + InitialState: []runtime.Object{ + makeTrigger(), + makeBroker(), + makeChannel(), + makeSubscriberService(), + makeK8sService(), + makeVirtualService(), + makeDifferentSubscription(), + }, + Mocks: controllertesting.Mocks{ + MockDeletes: []controllertesting.MockDelete{ + func(_ client.Client, _ context.Context, obj runtime.Object) (controllertesting.MockHandled, error) { + if _, ok := obj.(*v1alpha1.Subscription); ok { + return controllertesting.Handled, errors.New("test error deleting subscription") + } + return controllertesting.Unhandled, nil + }, + }, + }, + WantErrMsg: "test error deleting subscription", + WantEvent: []corev1.Event{events[subscriptionDeleteFailed], events[triggerReconcileFailed]}, + }, } for _, tc := range testCases { c := tc.GetClient() @@ -416,11 +467,11 @@ func makeChannelProvisioner() *corev1.ObjectReference { } } -func makeChannel() *v1alpha1.Channel { +func newChannel(name string) *v1alpha1.Channel { return &v1alpha1.Channel{ ObjectMeta: metav1.ObjectMeta{ - Namespace: testNS, - GenerateName: fmt.Sprintf("%s-broker-", brokerName), + Namespace: testNS, + Name: name, Labels: map[string]string{ "eventing.knative.dev/broker": brokerName, "eventing.knative.dev/brokerEverything": "true", @@ -440,6 +491,14 @@ func makeChannel() *v1alpha1.Channel { } } +func makeChannel() *v1alpha1.Channel { + return newChannel(fmt.Sprintf("%s-broker", brokerName)) +} + +func makeDifferentChannel() *v1alpha1.Channel { + return newChannel(fmt.Sprintf("%s-broker-different", brokerName)) +} + func makeSubscriberService() *corev1.Service { return &corev1.Service{ ObjectMeta: metav1.ObjectMeta{ @@ -485,6 +544,10 @@ func makeDifferentVirtualService() *istiov1alpha3.VirtualService { return vsvc } +func makeDifferentSubscription() *v1alpha1.Subscription { + return makeSubscription(makeTrigger(), makeDifferentChannel(), makeK8sService()) +} + func getOwnerReference() metav1.OwnerReference { return metav1.OwnerReference{ APIVersion: v1alpha1.SchemeGroupVersion.String(), From ae040072a7d2ef575cb5bf9716ae2b97e0b0a6f4 Mon Sep 17 00:00:00 2001 From: nachocano Date: Thu, 14 Feb 2019 18:01:30 -0800 Subject: [PATCH 059/221] More UTs --- .../v1alpha1/trigger/trigger_test.go | 76 ++++++++++++++++++- 1 file changed, 75 insertions(+), 1 deletion(-) diff --git a/pkg/reconciler/v1alpha1/trigger/trigger_test.go b/pkg/reconciler/v1alpha1/trigger/trigger_test.go index c5c6a59b1fc..bb1b8e0336e 100644 --- a/pkg/reconciler/v1alpha1/trigger/trigger_test.go +++ b/pkg/reconciler/v1alpha1/trigger/trigger_test.go @@ -22,6 +22,8 @@ import ( "fmt" "testing" + "github.com/knative/eventing/pkg/provisioners" + "github.com/knative/eventing/pkg/reconciler/names" "k8s.io/apimachinery/pkg/runtime" @@ -375,6 +377,73 @@ func TestReconcile(t *testing.T) { WantErrMsg: "test error deleting subscription", WantEvent: []corev1.Event{events[subscriptionDeleteFailed], events[triggerReconcileFailed]}, }, + { + Name: "Re-create Subscription error", + Scheme: scheme.Scheme, + InitialState: []runtime.Object{ + makeTrigger(), + makeBroker(), + makeChannel(), + makeSubscriberService(), + makeK8sService(), + makeVirtualService(), + makeDifferentSubscription(), + }, + Mocks: controllertesting.Mocks{ + MockCreates: []controllertesting.MockCreate{ + func(_ client.Client, _ context.Context, obj runtime.Object) (controllertesting.MockHandled, error) { + if _, ok := obj.(*v1alpha1.Subscription); ok { + return controllertesting.Handled, errors.New("test error re-creating subscription") + } + return controllertesting.Unhandled, nil + }, + }, + }, + WantErrMsg: "test error re-creating subscription", + WantEvent: []corev1.Event{events[subscriptionCreateFailed], events[triggerReconcileFailed]}, + }, + { + Name: "Update status error", + Scheme: scheme.Scheme, + InitialState: []runtime.Object{ + makeTrigger(), + makeBroker(), + makeChannel(), + makeSubscriberService(), + makeK8sService(), + makeVirtualService(), + makeSameSubscription(), + }, + Mocks: controllertesting.Mocks{ + MockStatusUpdates: []controllertesting.MockStatusUpdate{ + func(_ client.Client, _ context.Context, obj runtime.Object) (controllertesting.MockHandled, error) { + if _, ok := obj.(*v1alpha1.Trigger); ok { + return controllertesting.Handled, errors.New("test error updating trigger status") + } + return controllertesting.Unhandled, nil + }, + }, + }, + WantErrMsg: "test error updating trigger status", + WantEvent: []corev1.Event{events[triggerReconciled], events[triggerUpdateStatusFailed]}, + }, + { + Name: "Trigger reconciliation success", + Scheme: scheme.Scheme, + InitialState: []runtime.Object{ + makeTrigger(), + makeBroker(), + makeChannel(), + makeSubscriberService(), + makeK8sService(), + makeVirtualService(), + makeSameSubscription(), + }, + WantEvent: []corev1.Event{events[triggerReconciled]}, + WantPresent: []runtime.Object{ + makeReadyTrigger(), + }, + }, } for _, tc := range testCases { c := tc.GetClient() @@ -426,9 +495,10 @@ func makeTrigger() *v1alpha1.Trigger { func makeReadyTrigger() *v1alpha1.Trigger { t := makeTrigger() + provisioners.AddFinalizer(t, finalizerName) t.Status.InitializeConditions() t.Status.MarkBrokerExists() - t.Status.SubscriberURI = fmt.Sprintf("%s-trigger.%s.svc.cluster.local", triggerName, testNS) + t.Status.SubscriberURI = fmt.Sprintf("http://%s.%s.svc.cluster.local/", subscriberName, testNS) t.Status.MarkKubernetesServiceExists() t.Status.MarkVirtualServiceExists() t.Status.MarkSubscribed() @@ -544,6 +614,10 @@ func makeDifferentVirtualService() *istiov1alpha3.VirtualService { return vsvc } +func makeSameSubscription() *v1alpha1.Subscription { + return makeSubscription(makeTrigger(), makeChannel(), makeK8sService()) +} + func makeDifferentSubscription() *v1alpha1.Subscription { return makeSubscription(makeTrigger(), makeDifferentChannel(), makeK8sService()) } From 9c63dbcc5a35ec861d5b14fe828ab8e67a9c88c6 Mon Sep 17 00:00:00 2001 From: Adam Harwayne Date: Thu, 14 Feb 2019 18:32:32 -0800 Subject: [PATCH 060/221] Namespace reconciler automatically creates the Broker Filter's ServiceAccount and RBAC. Sadly this doesn't work well because we have such an old version of controller-runtime that the Filter ends up trying to watch _all_ Triggers, not just those in its namespace. And it only gets permission for the Triggers in its own namespace. --- config/200-broker-clusterrole.yaml | 28 ++++ config/500-controller.yaml | 2 +- pkg/broker/receiver.go | 4 + .../v1alpha1/namespace/namespace.go | 130 +++++++++++++++++- .../v1alpha1/namespace/namespace_test.go | 1 + sa.yaml | 20 --- t3.yaml | 16 +++ t4.yaml | 11 ++ 8 files changed, 186 insertions(+), 26 deletions(-) create mode 100644 config/200-broker-clusterrole.yaml delete mode 100644 sa.yaml create mode 100644 t3.yaml create mode 100644 t4.yaml diff --git a/config/200-broker-clusterrole.yaml b/config/200-broker-clusterrole.yaml new file mode 100644 index 00000000000..fc430c0dc8f --- /dev/null +++ b/config/200-broker-clusterrole.yaml @@ -0,0 +1,28 @@ +# Copyright 2019 The Knative Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: eventing-broker-filter +rules: + - apiGroups: + - eventing.knative.dev + resources: + - triggers + - triggers/status + verbs: + - get + - list + - watch diff --git a/config/500-controller.yaml b/config/500-controller.yaml index 15d76a8cf3a..55303c24745 100644 --- a/config/500-controller.yaml +++ b/config/500-controller.yaml @@ -42,7 +42,7 @@ spec: - name: FILTER_IMAGE value: github.com/knative/eventing/cmd/broker/filter - name: FILTER_SERVICE_ACCOUNT - value: broker-filter + value: eventing-broker-filter volumeMounts: - name: config-logging mountPath: /etc/config-logging diff --git a/pkg/broker/receiver.go b/pkg/broker/receiver.go index d51c3d6c755..9dd264337ee 100644 --- a/pkg/broker/receiver.go +++ b/pkg/broker/receiver.go @@ -83,6 +83,10 @@ func (r *Receiver) sendEvent(channel provisioners.ChannelReference, message *pro } func (r *Receiver) getTrigger(ctx context.Context, ref provisioners.ChannelReference) (*eventingv1alpha1.Trigger, error) { + // Sadly this doesn't work well because we do not yet have + // https://github.com/kubernetes-sigs/controller-runtime/pull/136, so controller runtime watches + // all Triggers, not just those in this namespace. And it doesn't have the RBAC (by default) for + // that to work. t := &eventingv1alpha1.Trigger{} err := r.client.Get(ctx, types.NamespacedName{ diff --git a/pkg/reconciler/v1alpha1/namespace/namespace.go b/pkg/reconciler/v1alpha1/namespace/namespace.go index 1c2c31ca618..a0742b8a4e9 100644 --- a/pkg/reconciler/v1alpha1/namespace/namespace.go +++ b/pkg/reconciler/v1alpha1/namespace/namespace.go @@ -18,11 +18,13 @@ package namespace import ( "context" + "fmt" "github.com/knative/eventing/contrib/gcppubsub/pkg/util/logging" "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" "go.uber.org/zap" "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" "k8s.io/apimachinery/pkg/api/errors" k8serrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -45,10 +47,16 @@ const ( controllerAgentName = "knative-eventing-namespace-controller" defaultBroker = "default" + brokerFilterSA = "eventing-broker-filter" + brokerFilterRB = "eventing-broker-filter" + brokerFilterClusterRole = "eventing-broker-filter" + knativeEventingAnnotation = "eventing.knative.dev/inject" // Name of the corev1.Events emitted from the reconciliation process. brokerCreated = "BrokerCreated" + serviceAccountCreated = "BrokerFilterServiceAccountCreated" + serviceAccountRBACCreated = "BrokerFilterServiceAccountRBACCreated" ) type reconciler struct { @@ -84,7 +92,7 @@ func ProvideController(logger *zap.Logger) func(manager.Manager) (controller.Con } // Watch all the resources that this reconciler reconciles. - for _, t := range []runtime.Object{ &v1alpha1.Broker{} } { + for _, t := range []runtime.Object{ &corev1.ServiceAccount{}, &rbacv1.RoleBinding{}, &v1alpha1.Broker{} } { err = c.Watch(&source.Kind{Type: t}, &handler.EnqueueRequestsFromMapFunc{ToRequests: &namespaceMapper{}}); if err != nil { return nil, err @@ -165,7 +173,17 @@ func (r *reconciler) reconcile(ctx context.Context, ns *corev1.Namespace) error return nil } - _, err := r.reconcileBroker(ctx, ns) + sa, err := r.reconcileBrokerFilterServiceAccount(ctx, ns) + if err != nil { + logging.FromContext(ctx).Error("Unable to reconcile the Broker Filter Service Account for the namespace", zap.Error(err)) + return err + } + _, err = r.reconcileBrokerFilterRBAC(ctx, ns, sa) + if err != nil { + logging.FromContext(ctx).Error("Unable to reconcile the Broker Filter Service Account RBAC for the namespace", zap.Error(err)) + return err + } + _, err = r.reconcileBroker(ctx, ns) if err != nil { logging.FromContext(ctx).Error("Unable to reconcile broker for the namespace", zap.Error(err)) return err @@ -174,6 +192,108 @@ func (r *reconciler) reconcile(ctx context.Context, ns *corev1.Namespace) error return nil } +func (r *reconciler) reconcileBrokerFilterServiceAccount(ctx context.Context, ns *corev1.Namespace) (*corev1.ServiceAccount, error) { + current, err := r.getBrokerFilterServiceAccount(ctx, ns) + + // If the resource doesn't exist, we'll create it. + if k8serrors.IsNotFound(err) { + sa := newBrokerFilterServiceAccount(ns) + err = r.client.Create(ctx, sa) + if err != nil { + return nil, err + } + r.recorder.Event(ns, + corev1.EventTypeNormal, + serviceAccountCreated, + fmt.Sprintf("Service account created for the Broker '%s'", sa.Name)) + return sa, nil + } else if err != nil { + return nil, err + } + // Don't update anything that is already present. + return current, nil +} + +func (r *reconciler) getBrokerFilterServiceAccount(ctx context.Context, ns *corev1.Namespace) (*corev1.ServiceAccount, error) { + sa := &corev1.ServiceAccount{} + name := types.NamespacedName{ + Namespace: ns.Name, + Name: brokerFilterSA, + } + err := r.client.Get(ctx, name, sa) + return sa, err +} + +func newBrokerFilterServiceAccount(ns *corev1.Namespace) *corev1.ServiceAccount { + return &corev1.ServiceAccount{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: ns.Name, + Name: brokerFilterSA, + Labels: injectedLabels(), + }, + } +} + +func injectedLabels() map[string]string { + return map[string]string{ + "eventing.knative.dev/namespaceInjected": "true", + } +} + +func (r *reconciler) reconcileBrokerFilterRBAC(ctx context.Context, ns *corev1.Namespace, sa *corev1.ServiceAccount) (*rbacv1.RoleBinding, error) { + current, err := r.getBrokerFilterRBAC(ctx, ns) + + // If the resource doesn't exist, we'll create it. + if k8serrors.IsNotFound(err) { + rbac := newBrokerFilterRBAC(ns, sa) + err = r.client.Create(ctx, rbac) + if err != nil { + return nil, err + } + r.recorder.Event(ns, + corev1.EventTypeNormal, + serviceAccountRBACCreated, + fmt.Sprintf("Service account RBAC created for the Broker Filter '%s'", rbac.Name)) + return rbac, nil + } else if err != nil { + return nil, err + } + // Don't update anything that is already present. + return current, nil +} + +func (r *reconciler) getBrokerFilterRBAC(ctx context.Context, ns *corev1.Namespace) (*rbacv1.RoleBinding, error) { + rb := &rbacv1.RoleBinding{} + name := types.NamespacedName{ + Namespace: ns.Name, + Name: brokerFilterRB, + } + err := r.client.Get(ctx, name, rb) + return rb, err +} + +func newBrokerFilterRBAC(ns *corev1.Namespace, sa *corev1.ServiceAccount) *rbacv1.RoleBinding { + return &rbacv1.RoleBinding{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: ns.Name, + Name: brokerFilterRB, + Labels: injectedLabels(), + }, + RoleRef:rbacv1.RoleRef{ + APIGroup:"rbac.authorization.k8s.io", + Kind: "ClusterRole", + Name: brokerFilterClusterRole, + }, + Subjects:[]rbacv1.Subject{ + { + Kind: "ServiceAccount", + Namespace: ns.Name, + Name: sa.Name, + }, + }, + } +} + func (r *reconciler) getBroker(ctx context.Context, ns *corev1.Namespace) (*v1alpha1.Broker, error) { b := &v1alpha1.Broker{} name := types.NamespacedName{ @@ -214,7 +334,7 @@ func newBroker(ns *corev1.Namespace) *v1alpha1.Broker { } func brokerLabels() map[string]string { - return map[string]string{ - "eventing.knative.dev/brokerForNamespace": "true", - } + l := injectedLabels() + l["eventing.knative.dev/brokerForNamespace"] = "true" + return l } diff --git a/pkg/reconciler/v1alpha1/namespace/namespace_test.go b/pkg/reconciler/v1alpha1/namespace/namespace_test.go index a3ce6a05615..14b1f6997aa 100644 --- a/pkg/reconciler/v1alpha1/namespace/namespace_test.go +++ b/pkg/reconciler/v1alpha1/namespace/namespace_test.go @@ -309,6 +309,7 @@ func makeBroker() *v1alpha1.Broker { Namespace: testNS, Name: brokerName, Labels: map[string]string{ + "eventing.knative.dev/namespaceInjected": "true", "eventing.knative.dev/brokerForNamespace": "true", }, }, diff --git a/sa.yaml b/sa.yaml deleted file mode 100644 index 124edb3f340..00000000000 --- a/sa.yaml +++ /dev/null @@ -1,20 +0,0 @@ -apiVersion: v1 -kind: ServiceAccount -metadata: - name: broker-filter - namespace: default - ---- - -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: broker-filter -subjects: - - kind: ServiceAccount - name: broker-filter - namespace: default -roleRef: - kind: ClusterRole - name: cluster-admin - apiGroup: rbac.authorization.k8s.io diff --git a/t3.yaml b/t3.yaml new file mode 100644 index 00000000000..0ea783d5675 --- /dev/null +++ b/t3.yaml @@ -0,0 +1,16 @@ +apiVersion: eventing.knative.dev/v1alpha1 +kind: Trigger +metadata: + name: t +spec: + # Our Cloud Event parsing library seems to have a bug and forces to put type and source in double + # quotes (as it thinks the actual value is `"foo"`, not `foo`). + filter: + sourceAndType: + type: '"com.example.someevent"' + source: '"/mycontext/subcontext"' + subscriber: + ref: + apiVersion: v1 + kind: Service + name: svc diff --git a/t4.yaml b/t4.yaml new file mode 100644 index 00000000000..a6a981bfc0b --- /dev/null +++ b/t4.yaml @@ -0,0 +1,11 @@ +apiVersion: eventing.knative.dev/v1alpha1 +kind: Trigger +metadata: + name: t +spec: + subscriber: + ref: + apiVersion: v1 + kind: Service + name: svc + From 3ad193f767303ad86128382dc10ef5d7eea8d24d Mon Sep 17 00:00:00 2001 From: Adam Harwayne Date: Thu, 14 Feb 2019 22:12:44 -0800 Subject: [PATCH 061/221] Remove no longer needed label. --- pkg/reconciler/v1alpha1/namespace/namespace.go | 8 +------- pkg/reconciler/v1alpha1/namespace/namespace_test.go | 1 - 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/pkg/reconciler/v1alpha1/namespace/namespace.go b/pkg/reconciler/v1alpha1/namespace/namespace.go index a0742b8a4e9..483d659604d 100644 --- a/pkg/reconciler/v1alpha1/namespace/namespace.go +++ b/pkg/reconciler/v1alpha1/namespace/namespace.go @@ -328,13 +328,7 @@ func newBroker(ns *corev1.Namespace) *v1alpha1.Broker { ObjectMeta: metav1.ObjectMeta{ Namespace: ns.Name, Name: defaultBroker, - Labels: brokerLabels(), + Labels: injectedLabels(), }, } } - -func brokerLabels() map[string]string { - l := injectedLabels() - l["eventing.knative.dev/brokerForNamespace"] = "true" - return l -} diff --git a/pkg/reconciler/v1alpha1/namespace/namespace_test.go b/pkg/reconciler/v1alpha1/namespace/namespace_test.go index 14b1f6997aa..9f3364caff1 100644 --- a/pkg/reconciler/v1alpha1/namespace/namespace_test.go +++ b/pkg/reconciler/v1alpha1/namespace/namespace_test.go @@ -310,7 +310,6 @@ func makeBroker() *v1alpha1.Broker { Name: brokerName, Labels: map[string]string{ "eventing.knative.dev/namespaceInjected": "true", - "eventing.knative.dev/brokerForNamespace": "true", }, }, } From d18acab2c478a9566c4ff749c08da8a5b9c07683 Mon Sep 17 00:00:00 2001 From: nachocano Date: Fri, 15 Feb 2019 12:10:25 -0800 Subject: [PATCH 062/221] Broker and trigger types UTs --- .../eventing/v1alpha1/broker_types_test.go | 271 +++++++++++++++++ .../eventing/v1alpha1/trigger_types_test.go | 272 ++++++++++++++++++ 2 files changed, 543 insertions(+) create mode 100644 pkg/apis/eventing/v1alpha1/broker_types_test.go create mode 100644 pkg/apis/eventing/v1alpha1/trigger_types_test.go diff --git a/pkg/apis/eventing/v1alpha1/broker_types_test.go b/pkg/apis/eventing/v1alpha1/broker_types_test.go new file mode 100644 index 00000000000..c5745150009 --- /dev/null +++ b/pkg/apis/eventing/v1alpha1/broker_types_test.go @@ -0,0 +1,271 @@ +/* +Copyright 2018 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" + corev1 "k8s.io/api/core/v1" +) + +var brokerConditionReady = duckv1alpha1.Condition{ + Type: BrokerConditionReady, + Status: corev1.ConditionTrue, +} + +var brokerConditionIngress = duckv1alpha1.Condition{ + Type: BrokerConditionIngress, + Status: corev1.ConditionTrue, +} + +var brokerConditionChannel = duckv1alpha1.Condition{ + Type: BrokerConditionChannel, + Status: corev1.ConditionTrue, +} + +var brokerConditionFilter = duckv1alpha1.Condition{ + Type: BrokerConditionFilter, + Status: corev1.ConditionTrue, +} + +var brokerConditionAddressable = duckv1alpha1.Condition{ + Type: BrokerConditionAddressable, + Status: corev1.ConditionFalse, +} + +func TestBrokerGetCondition(t *testing.T) { + tests := []struct { + name string + bs *BrokerStatus + condQuery duckv1alpha1.ConditionType + want *duckv1alpha1.Condition + }{{ + name: "single condition", + bs: &BrokerStatus{ + Conditions: []duckv1alpha1.Condition{ + brokerConditionReady, + }, + }, + condQuery: duckv1alpha1.ConditionReady, + want: &brokerConditionReady, + }, { + name: "multiple conditions", + bs: &BrokerStatus{ + Conditions: []duckv1alpha1.Condition{ + brokerConditionIngress, + brokerConditionChannel, + brokerConditionFilter, + }, + }, + condQuery: BrokerConditionFilter, + want: &brokerConditionFilter, + }, { + name: "multiple conditions, condition false", + bs: &BrokerStatus{ + Conditions: []duckv1alpha1.Condition{ + brokerConditionChannel, + brokerConditionFilter, + brokerConditionAddressable, + }, + }, + condQuery: BrokerConditionAddressable, + want: &brokerConditionAddressable, + }, { + name: "unknown condition", + bs: &BrokerStatus{ + Conditions: []duckv1alpha1.Condition{ + brokerConditionAddressable, + brokerConditionReady, + }, + }, + condQuery: duckv1alpha1.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{ + Conditions: []duckv1alpha1.Condition{{ + Type: BrokerConditionAddressable, + Status: corev1.ConditionUnknown, + }, { + Type: BrokerConditionChannel, + Status: corev1.ConditionUnknown, + }, { + Type: BrokerConditionFilter, + Status: corev1.ConditionUnknown, + }, { + Type: BrokerConditionIngress, + Status: corev1.ConditionUnknown, + }, { + Type: BrokerConditionReady, + Status: corev1.ConditionUnknown, + }}, + }, + }, { + name: "one false", + bs: &BrokerStatus{ + Conditions: []duckv1alpha1.Condition{{ + Type: BrokerConditionChannel, + Status: corev1.ConditionFalse, + }}, + }, + want: &BrokerStatus{ + Conditions: []duckv1alpha1.Condition{{ + Type: BrokerConditionAddressable, + Status: corev1.ConditionUnknown, + }, { + Type: BrokerConditionChannel, + Status: corev1.ConditionFalse, + }, { + Type: BrokerConditionFilter, + Status: corev1.ConditionUnknown, + }, { + Type: BrokerConditionIngress, + Status: corev1.ConditionUnknown, + }, { + Type: BrokerConditionReady, + Status: corev1.ConditionUnknown, + }}, + }, + }, { + name: "one true", + bs: &BrokerStatus{ + Conditions: []duckv1alpha1.Condition{{ + Type: BrokerConditionFilter, + Status: corev1.ConditionTrue, + }}, + }, + want: &BrokerStatus{ + Conditions: []duckv1alpha1.Condition{{ + Type: BrokerConditionAddressable, + Status: corev1.ConditionUnknown, + }, { + Type: BrokerConditionChannel, + Status: corev1.ConditionUnknown, + }, { + Type: BrokerConditionFilter, + Status: corev1.ConditionTrue, + }, { + Type: BrokerConditionIngress, + Status: corev1.ConditionUnknown, + }, { + Type: BrokerConditionReady, + 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 + markChannelReady bool + markFilterReady bool + markIngressReady bool + address string + wantReady bool + }{{ + name: "all happy", + markChannelReady: true, + markFilterReady: true, + markIngressReady: true, + address: "hostname", + wantReady: true, + }, { + name: "channel sad", + markChannelReady: false, + markFilterReady: true, + markIngressReady: true, + address: "hostname", + wantReady: false, + }, { + name: "filter sad", + markChannelReady: true, + markFilterReady: false, + markIngressReady: true, + address: "hostname", + wantReady: false, + }, { + name: "ingress sad", + markChannelReady: true, + markFilterReady: true, + markIngressReady: false, + address: "hostname", + wantReady: false, + }, { + name: "addressable sad", + markChannelReady: true, + markFilterReady: true, + markIngressReady: true, + address: "", + wantReady: false, + }, { + name: "all sad", + markChannelReady: false, + markFilterReady: false, + markIngressReady: false, + address: "", + wantReady: false, + }} + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + ts := &BrokerStatus{} + if test.markChannelReady { + ts.MarkChannelReady() + } + if test.markFilterReady { + ts.MarkFilterReady() + } + if test.markIngressReady { + ts.MarkIngressReady() + } + ts.SetAddress(test.address) + got := ts.IsReady() + if test.wantReady != got { + t.Errorf("unexpected readiness: want %v, got %v", test.wantReady, got) + } + }) + } +} diff --git a/pkg/apis/eventing/v1alpha1/trigger_types_test.go b/pkg/apis/eventing/v1alpha1/trigger_types_test.go new file mode 100644 index 00000000000..fc08fd0d6a0 --- /dev/null +++ b/pkg/apis/eventing/v1alpha1/trigger_types_test.go @@ -0,0 +1,272 @@ +/* +Copyright 2018 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" + corev1 "k8s.io/api/core/v1" +) + +var triggerConditionReady = duckv1alpha1.Condition{ + Type: TriggerConditionReady, + Status: corev1.ConditionTrue, +} + +var triggerConditionBrokerExists = duckv1alpha1.Condition{ + Type: TriggerConditionBrokerExists, + Status: corev1.ConditionTrue, +} + +var triggerConditionKubernetesService = duckv1alpha1.Condition{ + Type: TriggerConditionKubernetesService, + Status: corev1.ConditionTrue, +} + +var triggerConditionVirtualService = duckv1alpha1.Condition{ + Type: TriggerConditionVirtualService, + Status: corev1.ConditionTrue, +} + +var triggerConditionSubscribed = duckv1alpha1.Condition{ + Type: TriggerConditionSubscribed, + Status: corev1.ConditionFalse, +} + +func TestTriggerGetCondition(t *testing.T) { + tests := []struct { + name string + ts *TriggerStatus + condQuery duckv1alpha1.ConditionType + want *duckv1alpha1.Condition + }{{ + name: "single condition", + ts: &TriggerStatus{ + Conditions: []duckv1alpha1.Condition{ + triggerConditionReady, + }, + }, + condQuery: duckv1alpha1.ConditionReady, + want: &triggerConditionReady, + }, { + name: "multiple conditions", + ts: &TriggerStatus{ + Conditions: []duckv1alpha1.Condition{ + triggerConditionBrokerExists, + triggerConditionKubernetesService, + }, + }, + condQuery: TriggerConditionKubernetesService, + want: &triggerConditionKubernetesService, + }, { + name: "multiple conditions, condition false", + ts: &TriggerStatus{ + Conditions: []duckv1alpha1.Condition{ + triggerConditionBrokerExists, + triggerConditionKubernetesService, + triggerConditionSubscribed, + }, + }, + condQuery: TriggerConditionSubscribed, + want: &triggerConditionSubscribed, + }, { + name: "unknown condition", + ts: &TriggerStatus{ + Conditions: []duckv1alpha1.Condition{ + triggerConditionVirtualService, + triggerConditionSubscribed, + }, + }, + condQuery: duckv1alpha1.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{ + Conditions: []duckv1alpha1.Condition{{ + Type: TriggerConditionBrokerExists, + Status: corev1.ConditionUnknown, + }, { + Type: TriggerConditionKubernetesService, + Status: corev1.ConditionUnknown, + }, { + Type: TriggerConditionReady, + Status: corev1.ConditionUnknown, + }, { + Type: TriggerConditionSubscribed, + Status: corev1.ConditionUnknown, + }, { + Type: TriggerConditionVirtualService, + Status: corev1.ConditionUnknown, + }}, + }, + }, { + name: "one false", + ts: &TriggerStatus{ + Conditions: []duckv1alpha1.Condition{{ + Type: TriggerConditionVirtualService, + Status: corev1.ConditionFalse, + }}, + }, + want: &TriggerStatus{ + Conditions: []duckv1alpha1.Condition{{ + Type: TriggerConditionBrokerExists, + Status: corev1.ConditionUnknown, + }, { + Type: TriggerConditionKubernetesService, + Status: corev1.ConditionUnknown, + }, { + Type: TriggerConditionReady, + Status: corev1.ConditionUnknown, + }, { + Type: TriggerConditionSubscribed, + Status: corev1.ConditionUnknown, + }, { + Type: TriggerConditionVirtualService, + Status: corev1.ConditionFalse, + }}, + }, + }, { + name: "one true", + ts: &TriggerStatus{ + Conditions: []duckv1alpha1.Condition{{ + Type: TriggerConditionSubscribed, + Status: corev1.ConditionTrue, + }}, + }, + want: &TriggerStatus{ + Conditions: []duckv1alpha1.Condition{{ + Type: TriggerConditionBrokerExists, + Status: corev1.ConditionUnknown, + }, { + Type: TriggerConditionKubernetesService, + Status: corev1.ConditionUnknown, + }, { + Type: TriggerConditionReady, + Status: corev1.ConditionUnknown, + }, { + Type: TriggerConditionSubscribed, + Status: corev1.ConditionTrue, + }, { + Type: TriggerConditionVirtualService, + Status: corev1.ConditionUnknown, + }}, + }, + }} + + 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 TestTriggerIsReady(t *testing.T) { + tests := []struct { + name string + markBrokerExists bool + markKubernetesServiceExists bool + markVirtualServiceExists bool + markSubscribed bool + wantReady bool + }{{ + name: "all happy", + markBrokerExists: true, + markKubernetesServiceExists: true, + markVirtualServiceExists: true, + markSubscribed: true, + wantReady: true, + }, { + name: "broker sad", + markBrokerExists: false, + markKubernetesServiceExists: true, + markVirtualServiceExists: true, + markSubscribed: true, + wantReady: false, + }, { + name: "k8s service sad", + markBrokerExists: true, + markKubernetesServiceExists: false, + markVirtualServiceExists: true, + markSubscribed: true, + wantReady: false, + }, { + name: "virtual service sad", + markBrokerExists: true, + markKubernetesServiceExists: true, + markVirtualServiceExists: false, + markSubscribed: true, + wantReady: false, + }, { + name: "subscribed sad", + markBrokerExists: true, + markKubernetesServiceExists: true, + markVirtualServiceExists: true, + markSubscribed: false, + wantReady: false, + }, { + name: "all sad", + markBrokerExists: false, + markKubernetesServiceExists: false, + markVirtualServiceExists: false, + markSubscribed: false, + wantReady: false, + }} + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + ts := &TriggerStatus{} + if test.markBrokerExists { + ts.MarkBrokerExists() + } + if test.markKubernetesServiceExists { + ts.MarkKubernetesServiceExists() + } + if test.markVirtualServiceExists { + ts.MarkVirtualServiceExists() + } + if test.markSubscribed { + ts.MarkSubscribed() + } + got := ts.IsReady() + if test.wantReady != got { + t.Errorf("unexpected readiness: want %v, got %v", test.wantReady, got) + } + }) + } +} From 2a02ba5dbe30f01344de5f828ef9d6deeffd62ad Mon Sep 17 00:00:00 2001 From: Grant Rodgers Date: Fri, 15 Feb 2019 12:58:09 -0800 Subject: [PATCH 063/221] WIP early E2E test --- test/crd.go | 27 ++++ test/crd_checks.go | 36 +++++ test/e2e/broker_filter_test.go | 231 +++++++++++++++++++++++++++++++++ test/e2e/builder/broker.go | 48 +++++++ test/e2e/builder/trigger.go | 74 +++++++++++ test/e2e/e2e.go | 22 ++++ test/e2e/fixtures.go | 108 +++++++++++++++ test/states.go | 14 ++ 8 files changed, 560 insertions(+) create mode 100644 test/e2e/broker_filter_test.go create mode 100644 test/e2e/builder/broker.go create mode 100644 test/e2e/builder/trigger.go create mode 100644 test/e2e/fixtures.go diff --git a/test/crd.go b/test/crd.go index cd365342a0e..0806b221a70 100644 --- a/test/crd.go +++ b/test/crd.go @@ -18,6 +18,7 @@ package test // crd contains functions that construct boilerplate CRD definitions. import ( + "fmt" "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" servingv1alpha1 "github.com/knative/serving/pkg/apis/serving/v1alpha1" corev1 "k8s.io/api/core/v1" @@ -166,6 +167,32 @@ func Subscription(name string, namespace string, channel *corev1.ObjectReference } } +func Broker(name string, namespace string) *v1alpha1.Broker { + return &v1alpha1.Broker{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + }, + Spec: v1alpha1.BrokerSpec{}, + } +} + +func Trigger(name string, namespace string, eventType string, subscriberRef *corev1.ObjectReference, brokerName string) *v1alpha1.Trigger { + return &v1alpha1.Trigger{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + }, + Spec: v1alpha1.TriggerSpec{ + Broker: brokerName, + Type: fmt.Sprintf("%q", eventType), + Subscriber: &v1alpha1.SubscriberSpec{ + Ref: subscriberRef, + }, + }, + } +} + // CloudEvent specifies the arguments for a CloudEvent sent by the sendevent // binary. type CloudEvent struct { diff --git a/test/crd_checks.go b/test/crd_checks.go index e66c7722024..f996b8e5fd0 100644 --- a/test/crd_checks.go +++ b/test/crd_checks.go @@ -91,3 +91,39 @@ func WaitForSubscriptionState(client eventingclient.SubscriptionInterface, name return inState(r) }) } + +// WaitForBrokerState polls the status of the Broker called name from client +// every interval until inState returns `true` indicating it is done, returns an +// error or timeout. desc will be used to name the metric that is emitted to +// track how long it took for name to get into the state checked by inState. +func WaitForBrokerState(client eventingclient.BrokerInterface, name string, inState func(r *eventingv1alpha1.Broker) (bool, error), desc string) error { + metricName := fmt.Sprintf("WaitForBrokerState/%s/%s", name, desc) + _, span := trace.StartSpan(context.Background(), metricName) + defer span.End() + + return wait.PollImmediate(interval, timeout, func() (bool, error) { + r, err := client.Get(name, metav1.GetOptions{}) + if err != nil { + return true, err + } + return inState(r) + }) +} + +// WaitForTriggerState polls the status of the Trigger called name from client +// every interval until inState returns `true` indicating it is done, returns an +// error or timeout. desc will be used to name the metric that is emitted to +// track how long it took for name to get into the state checked by inState. +func WaitForTriggerState(client eventingclient.TriggerInterface, name string, inState func(r *eventingv1alpha1.Trigger) (bool, error), desc string) error { + metricName := fmt.Sprintf("WaitForTriggerState/%s/%s", name, desc) + _, span := trace.StartSpan(context.Background(), metricName) + defer span.End() + + return wait.PollImmediate(interval, timeout, func() (bool, error) { + r, err := client.Get(name, metav1.GetOptions{}) + if err != nil { + return true, err + } + return inState(r) + }) +} diff --git a/test/e2e/broker_filter_test.go b/test/e2e/broker_filter_test.go new file mode 100644 index 00000000000..f42436dae2b --- /dev/null +++ b/test/e2e/broker_filter_test.go @@ -0,0 +1,231 @@ +// +build e2e + +/* +Copyright 2019 The Knative Authors +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT 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 e2e + +import ( + "fmt" + "testing" + "time" + + "github.com/knative/eventing/test" + pkgTest "github.com/knative/pkg/test" + "github.com/knative/pkg/test/logging" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/uuid" +) + +const ( + defaultBrokerName = "default" + altBrokerName = "alternate" + anyEvent = "Any" + untypedEvent = "test.untyped" + typedEvent = "test.typed" +) + +func triggerName(broker, eventType string) string { + fmt.Sprintf("%s-dump-%s", broker, eventType) +} + +func namespaceExists(t *testing.T, clients *test.Clients) (string, func()) { + logger := logging.GetContextLogger("TestBrokerFilter") + shutdown := func() {} + ns := pkgTest.Flags.Namespace + logger.Infof("Namespace: %s", ns) + + nsSpec, err := clients.Kube.Kube.CoreV1().Namespaces().Get(ns, metav1.GetOptions{}) + + if err != nil && errors.IsNotFound(err) { + nsSpec = &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: ns}} + logger.Infof("Creating Namespace: %s", ns) + nsSpec, err = clients.Kube.Kube.CoreV1().Namespaces().Create(nsSpec) + if err != nil { + t.Fatalf("Failed to create Namespace: %s; %v", ns, err) + } else { + shutdown = func() { + clients.Kube.Kube.CoreV1().Namespaces().Delete(nsSpec.Name, nil) + // TODO: this is a bit hacky but in order for the tests to work + // correctly for a clean namespace to be created we need to also + // wait for it to be removed. + // To fix this we could generate namespace names. + // This only happens when the namespace provided does not exist. + // + // wait up to 120 seconds for the namespace to be removed. + logger.Infof("Deleting Namespace: %s", ns) + for i := 0; i < 120; i++ { + time.Sleep(1 * time.Second) + if _, err := clients.Kube.Kube.CoreV1().Namespaces().Get(ns, metav1.GetOptions{}); err != nil && errors.IsNotFound(err) { + logger.Info("Namespace has been deleted") + // the namespace is gone. + break + } + } + } + } + } + return ns, shutdown +} + +func TestBrokerFilter(t *testing.T) { + logger := logging.GetContextLogger("TestBrokerFilter") + + clients, cleaner := Setup(t, logger) + defer TearDown(clients, cleaner, logger) + + // verify namespace + ns, cleanupNS := namespaceExists(t, clients) + defer cleanupNS() + + // Fixtures + + // TODO label namespace to get default Broker + + fixtures := []Fixture{ + // Default Any Trigger + &KnativeFixture{ + Object: builder.Trigger("default-dump-any"), pkgTest.Flags.Namespace). + Type(anyEvent). + SubscriberSvc("default-any-dumper"), + }, + // Default Typed Trigger + &KnativeFixture{ + Object: builder.Trigger("default-dump-typed"), pkgTest.Flags.Namespace). + Type(typedEvent). + SubscriberSvc("default-typed-dumper"), + }, + + // Alternate Broker + &KnativeFixture{ + Object: builder.Broker(altBrokerName, pkgTest.Flags.Namespace), + }, + // Alternate Any Trigger + &KnativeFixture{ + Object: builder.Trigger("alt-dump-any"), pkgTest.Flags.Namespace). + Broker(altBrokerName). + Type(anyEvent). + SubscriberSvc(fmt.Sprintf("alt-any-dumper"), + }, + // Alternate Typed Trigger + &KnativeFixture{ + Object: builder.Trigger("alt-dump-typed"), pkgTest.Flags.Namespace). + Broker(altBrokerName). + Type(typedEvent). + SubscriberSvc("alt-typed-dumper"), + }, + } + + ctx := context.Background() + + //TODO move this to runners + + for _, f := range fixtures { + f.Create(ctx, client) + } + + for _, f := range fixtures { + f.Verify(ctx, client) + } + + // Create message dumper services + // Create: pod + // Verify: pod status is ready + // + + pods := []Fixture{ + &PodSuccess{ + + } + } + + // create alt Broker + + // For each broker, create a typed and untyped trigger. + // For each trigger, create a logevents pod. + // Wait for Broker, triggers, and pods to become ready. + + // Take Action + + // For each tuple of typed and untyped, default and alt broker: + // create a sendevents pod to send an event of the type to the broker address + + // Verify + + // For each logevents pod: + // check logs to ensure the correct message(s) got there + + // create logger pod + + logger.Infof("creating subscriber pod") + selector := map[string]string{"e2etest": string(uuid.NewUUID())} + subscriberPod := test.EventLoggerPod(routeName, ns, selector) + if err := CreatePod(clients, subscriberPod, logger, cleaner); err != nil { + t.Fatalf("Failed to create event logger pod: %v", err) + } + if err := WaitForAllPodsRunning(clients, logger, ns); err != nil { + t.Fatalf("Error waiting for logger pod to become running: %v", err) + } + logger.Infof("subscriber pod running") + + subscriberSvc := test.Service(routeName, ns, selector) + if err := CreateService(clients, subscriberSvc, logger, cleaner); err != nil { + t.Fatalf("Failed to create event logger service: %v", err) + } + + // Reload subscriberPod to get IP + subscriberPod, err := clients.Kube.Kube.CoreV1().Pods(subscriberPod.Namespace).Get(subscriberPod.Name, metav1.GetOptions{}) + if err != nil { + t.Fatalf("Failed to get subscriber pod: %v", err) + } + + // create channel + + logger.Infof("Creating Channel and Subscription") + if test.EventingFlags.Provisioner == "" { + t.Fatal("ClusterChannelProvisioner must be set to a non-empty string. Either do not specify --clusterChannelProvisioner or set to something other than the empty string") + } + channel := test.Channel(channelName, ns, test.ClusterChannelProvisioner(test.EventingFlags.Provisioner)) + logger.Infof("channel: %#v", channel) + sub := test.Subscription(subscriptionName, ns, test.ChannelRef(channelName), test.SubscriberSpecForService(routeName), nil) + logger.Infof("sub: %#v", sub) + + if err := WithChannelAndSubscriptionReady(clients, channel, sub, logger, cleaner); err != nil { + t.Fatalf("The Channel or Subscription were not marked as Ready: %v", err) + } + + // create sender pod + + logger.Infof("Creating event sender") + body := fmt.Sprintf("TestSingleEvent %s", uuid.NewUUID()) + event := test.CloudEvent{ + Source: senderName, + Type: "test.eventing.knative.dev", + Data: fmt.Sprintf(`{"msg":%q}`, body), + Encoding: encoding, + } + url := fmt.Sprintf("http://%s", channel.Status.Address.Hostname) + pod := test.EventSenderPod(senderName, ns, url, event) + logger.Infof("sender pod: %#v", pod) + if err := CreatePod(clients, pod, logger, cleaner); err != nil { + t.Fatalf("Failed to create event sender pod: %v", err) + } + + if err := WaitForLogContent(clients, logger, routeName, subscriberPod.Spec.Containers[0].Name, ns, body); err != nil { + t.Fatalf("String %q not found in logs of subscriber pod %q: %v", body, routeName, err) + } +} diff --git a/test/e2e/builder/broker.go b/test/e2e/builder/broker.go new file mode 100644 index 00000000000..dc00c6245d3 --- /dev/null +++ b/test/e2e/builder/broker.go @@ -0,0 +1,48 @@ +/* +Copyright 2019 The Knative Authors +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT 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 builder + +import ( + eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +type BrokerBuilder struct { + *eventingv1alpha1.Broker +} + +func Broker(name, namespace string) *BrokerBuilder { + broker := &eventingv1alpha1.Broker{ + TypeMeta: metav1.TypeMeta{ + APIVersion: eventingv1alpha1.SchemeGroupVersion.String(), + Kind: "Broker", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + }, + Spec: eventingv1alpha1.BrokerSpec{}, + } + + return &BrokerBuilder{ + Broker: broker, + } +} + +func (b *BrokerBuilder) Build() runtime.Object { + return b.Broker.DeepCopy() +} \ No newline at end of file diff --git a/test/e2e/builder/trigger.go b/test/e2e/builder/trigger.go new file mode 100644 index 00000000000..745a71a34ad --- /dev/null +++ b/test/e2e/builder/trigger.go @@ -0,0 +1,74 @@ +/* +Copyright 2019 The Knative Authors +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT 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 builder + +import ( + eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +type TriggerBuilder struct { + *eventingv1alpha1.Trigger +} + +func Trigger(name, namespace string) *TriggerBuilder { + trigger := &eventingv1alpha1.Trigger{ + TypeMeta: metav1.TypeMeta{ + APIVersion: eventingv1alpha1.SchemeGroupVersion.String(), + Kind: "Trigger", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + }, + Spec: eventingv1alpha1.TriggerSpec{}, + } + + return &TriggerBuilder{ + Trigger: trigger, + } +} + +func (b *TriggerBuilder) Build() runtime.Object { + return b.Trigger.DeepCopy() +} + +func (b *TriggerBuilder) Type(eventType string) *TriggerBuilder { + b.Trigger.Spec.Type = eventType + return b +} + +func (b *TriggerBuilder) Broker(brokerName string) *TriggerBuilder { + b.Trigger.Spec.Broker = brokerName + return b +} + +func (b *TriggerBuilder) Subscriber(ref *corev1.ObjectReference) *TriggerBuilder { + b.Trigger.Spec.Subscriber.Ref = ref + return b +} + +func (b *TriggerBuilder) SubscriberSvc(svcName string) *TriggerBuilder { + b.Trigger.Spec.Subscriber.Ref = &corev1.ObjectReference{ + APIVersion: corev1.SchemeGroupVersion.String(), + Kind: "Service", + Name: svcName, + Namespace: b.Trigger.GetNamespace(), + } + return b +} \ No newline at end of file diff --git a/test/e2e/e2e.go b/test/e2e/e2e.go index a183ec5cb9c..453c0c69ea6 100644 --- a/test/e2e/e2e.go +++ b/test/e2e/e2e.go @@ -159,6 +159,28 @@ func WithChannelAndSubscriptionReady(clients *test.Clients, channel *v1alpha1.Ch return nil } +// CreateBroker will create a Broker +func CreateBroker(clients *test.Clients, broker *v1alpha1.Broker, logger *logging.BaseLogger, cleaner *test.Cleaner) error { + brokers := clients.Eventing.EventingV1alpha1().Brokers(pkgTest.Flags.Namespace) + res, err := brokers.Create(broker) + if err != nil { + return err + } + cleaner.Add(v1alpha1.SchemeGroupVersion.Group, v1alpha1.SchemeGroupVersion.Version, "brokers", pkgTest.Flags.Namespace, res.ObjectMeta.Name) + return nil +} + +// CreateTrigger will create a Trigger +func CreateTrigger(clients *test.Clients, trigger *v1alpha1.Trigger, logger *logging.BaseLogger, cleaner *test.Cleaner) error { + triggers := clients.Eventing.EventingV1alpha1().Triggers(pkgTest.Flags.Namespace) + res, err := triggers.Create(trigger) + if err != nil { + return err + } + cleaner.Add(v1alpha1.SchemeGroupVersion.Group, v1alpha1.SchemeGroupVersion.Version, "triggers", pkgTest.Flags.Namespace, res.ObjectMeta.Name) + return nil +} + // CreateServiceAccount will create a service account func CreateServiceAccount(clients *test.Clients, sa *corev1.ServiceAccount, logger *logging.BaseLogger, cleaner *test.Cleaner) error { sas := clients.Kube.Kube.CoreV1().ServiceAccounts(pkgTest.Flags.Namespace) diff --git a/test/e2e/fixtures.go b/test/e2e/fixtures.go new file mode 100644 index 00000000000..f2174c58048 --- /dev/null +++ b/test/e2e/fixtures.go @@ -0,0 +1,108 @@ +/* +Copyright 2019 The Knative Authors +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT 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 e2e + +import ( + "context" + "github.com/knative/eventing/pkg/reconciler/testing" + "github.com/knative/pkg/apis/duck" + duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" + "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + + "sigs.k8s.io/controller-runtime/pkg/client" +) + +type Fixture interface { + // Create attempts to instantiate the fixture. It may be called multiple times if earlier attempts return an error. + Create(context.Context, client.Client) error + + // Verify determines if the fixture was successfully instantiated once. It may be called multiple times if earlier + // attempts return false or an error. + Verify(context.Context, client.Client) (bool, error) + + // Debug surfaces context about a failure during Create or Verify. + Debug(context.Context, client.Client) + + // Teardown removes any state instantiated by Create or Verify. + Teardown(context.Context, client.Client) error +} + +type KnativeFixture struct { + Object testing.Buildable +} + +type CreateFunc func(context.Context, client.Client) error +type VerifyFunc func(context.Context, client.Client) (bool, error) +type DebugFunc func(context.Context, client.Client) +type TeardownFunc func(context.Context, client.Client) error + +type FixtureFuncs struct { + Create CreateFunc + Verify VerifyFunc + Debug DebugFunc + Teardown TeardownFunc +} + +//Fixtures: +// - Broker, Trigger Verify checks status ready +// - Sendevent Verify checks that pod completed successfully +// - Logevent Verify checks that the expected message was logged + +func (f *KnativeFixture) Create(ctx context.Context, cl client.Client) error { + obj := f.Object.Build() + err := cl.Create(ctx, obj) + if err != nil { + return err + } + return nil +} + +var standardCondSet = duckv1alpha1.NewLivingConditionSet() + +// TODO the runner should do this with backoff and retry. +// This method only verifies Knative objects +func (f *KnativeFixture) Verify(ctx context.Context, cl client.Client) (bool, error) { + obj := f.Object.Build() + u := &unstructured.Unstructured{} + acc, err := meta.Accessor(obj) + if err != nil { + return false, err + } + if err := cl.Get(ctx, client.ObjectKey{Name: acc.GetName(), Namespace: acc.GetNamespace()}, u); err != nil { + return false, err + } + + kr := &duckv1alpha1.KResource{} + if err := duck.FromUnstructured(u, kr); err != nil { + return false, err + } + + if !standardCondSet.Manage(kr.Status).IsHappy() { + return false, nil + } + + return true, nil +} + +// TODO If Create or Verify return an error, run this method, then Cleanup +func (f *KnativeFixture) Debug(ctx context.Context, cl client.Client) { +} + +// TODO if Teardown returns an error, log it and give up (maybe retry for a while?) +func (f *KnativeFixture) Teardownctx context.Context, cl client.Client) error { + obj := f.Object.Build() + return cl.Delete(ctx, obj) +} \ No newline at end of file diff --git a/test/states.go b/test/states.go index 49f4256435e..e5a8dd0cdcf 100644 --- a/test/states.go +++ b/test/states.go @@ -54,6 +54,20 @@ func IsSubscriptionReady(s *eventingv1alpha1.Subscription) (bool, error) { return s.Status.IsReady(), nil } +/ IsBrokerReady will check the status conditions of the Broker and return true +// if the Broker is ready. +func IsBrokerReady(b *eventingv1alpha1.Broker) (bool, error) { + return b.Status.IsReady(), nil +} + +// IsTriggerReady will check the status conditions of the Trigger and +// return true if the Trigger is ready. +func IsTriggerReady(t *eventingv1alpha1.Trigger) (bool, error) { + return t.Status.IsReady(), nil +} + + + // PodsRunning will check the status conditions of the pod list and return true // if all pods are Running. func PodsRunning(podList *corev1.PodList) (bool, error) { From 54cdb3cad27fb9806984aa0965fdeefe43226fcc Mon Sep 17 00:00:00 2001 From: nachocano Date: Tue, 19 Feb 2019 11:26:26 -0800 Subject: [PATCH 064/221] Changes after code review. Adding trigger defaults and validation tests --- .../eventing/v1alpha1/broker_types_test.go | 42 +-- .../v1alpha1/trigger_defaults_test.go | 72 +++++ .../eventing/v1alpha1/trigger_types_test.go | 42 +-- .../eventing/v1alpha1/trigger_validation.go | 2 +- .../v1alpha1/trigger_validation_test.go | 245 ++++++++++++++++++ 5 files changed, 362 insertions(+), 41 deletions(-) create mode 100644 pkg/apis/eventing/v1alpha1/trigger_defaults_test.go create mode 100644 pkg/apis/eventing/v1alpha1/trigger_validation_test.go diff --git a/pkg/apis/eventing/v1alpha1/broker_types_test.go b/pkg/apis/eventing/v1alpha1/broker_types_test.go index c5745150009..623a002b642 100644 --- a/pkg/apis/eventing/v1alpha1/broker_types_test.go +++ b/pkg/apis/eventing/v1alpha1/broker_types_test.go @@ -24,30 +24,32 @@ import ( corev1 "k8s.io/api/core/v1" ) -var brokerConditionReady = duckv1alpha1.Condition{ - Type: BrokerConditionReady, - Status: corev1.ConditionTrue, -} +var ( + brokerConditionReady = duckv1alpha1.Condition{ + Type: BrokerConditionReady, + Status: corev1.ConditionTrue, + } -var brokerConditionIngress = duckv1alpha1.Condition{ - Type: BrokerConditionIngress, - Status: corev1.ConditionTrue, -} + brokerConditionIngress = duckv1alpha1.Condition{ + Type: BrokerConditionIngress, + Status: corev1.ConditionTrue, + } -var brokerConditionChannel = duckv1alpha1.Condition{ - Type: BrokerConditionChannel, - Status: corev1.ConditionTrue, -} + brokerConditionChannel = duckv1alpha1.Condition{ + Type: BrokerConditionChannel, + Status: corev1.ConditionTrue, + } -var brokerConditionFilter = duckv1alpha1.Condition{ - Type: BrokerConditionFilter, - Status: corev1.ConditionTrue, -} + brokerConditionFilter = duckv1alpha1.Condition{ + Type: BrokerConditionFilter, + Status: corev1.ConditionTrue, + } -var brokerConditionAddressable = duckv1alpha1.Condition{ - Type: BrokerConditionAddressable, - Status: corev1.ConditionFalse, -} + brokerConditionAddressable = duckv1alpha1.Condition{ + Type: BrokerConditionAddressable, + Status: corev1.ConditionFalse, + } +) func TestBrokerGetCondition(t *testing.T) { tests := []struct { diff --git a/pkg/apis/eventing/v1alpha1/trigger_defaults_test.go b/pkg/apis/eventing/v1alpha1/trigger_defaults_test.go new file mode 100644 index 00000000000..a3dab313fb7 --- /dev/null +++ b/pkg/apis/eventing/v1alpha1/trigger_defaults_test.go @@ -0,0 +1,72 @@ +/* +Copyright 2019 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + "testing" + + "github.com/google/go-cmp/cmp" +) + +var ( + defaultBroker = "default" + otherBroker = "other_broker" + defaultTriggerFilter = &TriggerFilter{ + SourceAndType: &TriggerFilterSourceAndType{ + Type: TriggerAnyFilter, + Source: TriggerAnyFilter}, + } + otherTriggerFilter = &TriggerFilter{ + SourceAndType: &TriggerFilterSourceAndType{ + Type: "other_type", + Source: "other_source"}, + } + defaultTrigger = Trigger{ + Spec: TriggerSpec{ + Broker: defaultBroker, + Filter: defaultTriggerFilter, + }, + } +) + +func TestTriggerDefaults(t *testing.T) { + testCases := map[string]struct { + initial Trigger + expected Trigger + }{ + "nil broker": { + initial: Trigger{Spec: TriggerSpec{Filter: otherTriggerFilter}}, + expected: Trigger{Spec: TriggerSpec{Broker: defaultBroker, Filter: otherTriggerFilter}}, + }, + "nil filter": { + initial: Trigger{Spec: TriggerSpec{Broker: otherBroker}}, + expected: Trigger{Spec: TriggerSpec{Broker: otherBroker, Filter: defaultTriggerFilter}}, + }, + "nil broker and nil filter": { + initial: Trigger{}, + expected: defaultTrigger, + }, + } + for n, tc := range testCases { + t.Run(n, func(t *testing.T) { + tc.initial.SetDefaults() + if diff := cmp.Diff(tc.expected, tc.initial); diff != "" { + t.Fatalf("Unexpected defaults (-want, +got): %s", diff) + } + }) + } +} diff --git a/pkg/apis/eventing/v1alpha1/trigger_types_test.go b/pkg/apis/eventing/v1alpha1/trigger_types_test.go index fc08fd0d6a0..1d36e8fed7c 100644 --- a/pkg/apis/eventing/v1alpha1/trigger_types_test.go +++ b/pkg/apis/eventing/v1alpha1/trigger_types_test.go @@ -24,30 +24,32 @@ import ( corev1 "k8s.io/api/core/v1" ) -var triggerConditionReady = duckv1alpha1.Condition{ - Type: TriggerConditionReady, - Status: corev1.ConditionTrue, -} +var ( + triggerConditionReady = duckv1alpha1.Condition{ + Type: TriggerConditionReady, + Status: corev1.ConditionTrue, + } -var triggerConditionBrokerExists = duckv1alpha1.Condition{ - Type: TriggerConditionBrokerExists, - Status: corev1.ConditionTrue, -} + triggerConditionBrokerExists = duckv1alpha1.Condition{ + Type: TriggerConditionBrokerExists, + Status: corev1.ConditionTrue, + } -var triggerConditionKubernetesService = duckv1alpha1.Condition{ - Type: TriggerConditionKubernetesService, - Status: corev1.ConditionTrue, -} + triggerConditionKubernetesService = duckv1alpha1.Condition{ + Type: TriggerConditionKubernetesService, + Status: corev1.ConditionTrue, + } -var triggerConditionVirtualService = duckv1alpha1.Condition{ - Type: TriggerConditionVirtualService, - Status: corev1.ConditionTrue, -} + triggerConditionVirtualService = duckv1alpha1.Condition{ + Type: TriggerConditionVirtualService, + Status: corev1.ConditionTrue, + } -var triggerConditionSubscribed = duckv1alpha1.Condition{ - Type: TriggerConditionSubscribed, - Status: corev1.ConditionFalse, -} + triggerConditionSubscribed = duckv1alpha1.Condition{ + Type: TriggerConditionSubscribed, + Status: corev1.ConditionFalse, + } +) func TestTriggerGetCondition(t *testing.T) { tests := []struct { diff --git a/pkg/apis/eventing/v1alpha1/trigger_validation.go b/pkg/apis/eventing/v1alpha1/trigger_validation.go index 073784972b1..e58150fdf48 100644 --- a/pkg/apis/eventing/v1alpha1/trigger_validation.go +++ b/pkg/apis/eventing/v1alpha1/trigger_validation.go @@ -37,7 +37,7 @@ func (ts *TriggerSpec) Validate() *apis.FieldError { errs = errs.Also(fe) } - if ts.Filter.SourceAndType == nil { + if ts.Filter != nil && ts.Filter.SourceAndType == nil { fe := apis.ErrMissingField("filter.sourceAndType") errs = errs.Also(fe) } diff --git a/pkg/apis/eventing/v1alpha1/trigger_validation_test.go b/pkg/apis/eventing/v1alpha1/trigger_validation_test.go new file mode 100644 index 00000000000..8afa183faca --- /dev/null +++ b/pkg/apis/eventing/v1alpha1/trigger_validation_test.go @@ -0,0 +1,245 @@ +/* +Copyright 2019 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + "testing" + + "github.com/knative/pkg/apis" + + "github.com/google/go-cmp/cmp" + corev1 "k8s.io/api/core/v1" +) + +var ( + validTriggerFilter = &TriggerFilter{ + SourceAndType: &TriggerFilterSourceAndType{ + Type: "other_type", + Source: "other_source"}, + } + validSubscriber = &SubscriberSpec{ + Ref: &corev1.ObjectReference{ + Name: "subscriber_test", + Kind: "Service", + APIVersion: "serving.knative.dev/v1alpha1", + }, + } + invalidSubscriber = &SubscriberSpec{ + Ref: &corev1.ObjectReference{ + Kind: "Service", + APIVersion: "serving.knative.dev/v1alpha1", + }, + } +) + +func TestTriggerValidation(t *testing.T) { + name := "invalid trigger spec" + trigger := &Trigger{Spec: TriggerSpec{}} + + want := &apis.FieldError{ + Paths: []string{"spec.broker", "spec.filter", "spec.subscriber"}, + Message: "missing field(s)", + } + + t.Run(name, func(t *testing.T) { + got := trigger.Validate() + if diff := cmp.Diff(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 { + fe := apis.ErrMissingField("broker", "filter", "subscriber") + return fe + }(), + }, { + name: "missing broker", + ts: &TriggerSpec{ + Broker: "", + Filter: validTriggerFilter, + Subscriber: validSubscriber, + }, + want: func() *apis.FieldError { + fe := apis.ErrMissingField("broker") + return fe + }(), + }, { + name: "missing filter", + ts: &TriggerSpec{ + Broker: "test_broker", + Subscriber: validSubscriber, + }, + want: func() *apis.FieldError { + fe := apis.ErrMissingField("filter") + return fe + }(), + }, { + name: "missing filter.sourceAndType", + ts: &TriggerSpec{ + Broker: "test_broker", + Filter: &TriggerFilter{}, + Subscriber: validSubscriber, + }, + want: func() *apis.FieldError { + fe := apis.ErrMissingField("filter.sourceAndType") + return fe + }(), + }, { + name: "missing subscriber", + ts: &TriggerSpec{ + Broker: "test_broker", + Filter: validTriggerFilter, + }, + want: func() *apis.FieldError { + fe := apis.ErrMissingField("subscriber") + return fe + }(), + }, { + name: "missing subscriber.ref.name", + ts: &TriggerSpec{ + Broker: "test_broker", + Filter: validTriggerFilter, + Subscriber: invalidSubscriber, + }, + want: func() *apis.FieldError { + fe := apis.ErrMissingField("subscriber.ref.name") + return fe + }(), + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := test.ts.Validate() + 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: validTriggerFilter, + }, + }, + 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(test.original) + if diff := cmp.Diff(test.want.Error(), got.Error()); diff != "" { + t.Errorf("CheckImmutableFields (-want, +got) = %v", diff) + } + }) + } +} + +func TestTriggerInvalidImmutableType(t *testing.T) { + tests := []struct { + name string + current apis.Immutable + original apis.Immutable + want *apis.FieldError + }{{ + name: "invalid type", + current: &Trigger{ + Spec: TriggerSpec{ + Broker: "broker", + }, + }, + original: nil, + want: &apis.FieldError{ + Message: "The provided original was not a Trigger", + }, + }} + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := test.current.CheckImmutableFields(test.original) + if diff := cmp.Diff(test.want.Error(), got.Error()); diff != "" { + t.Errorf("CheckImmutableType (-want, +got) = %v", diff) + } + }) + } +} From 11a1734e1706b290322c875d880a36dc488ce1d5 Mon Sep 17 00:00:00 2001 From: nachocano Date: Tue, 19 Feb 2019 11:44:04 -0800 Subject: [PATCH 065/221] Cleaner trigger validation --- .../v1alpha1/broker_validation_test.go | 17 +++++++ .../eventing/v1alpha1/trigger_validation.go | 7 +-- .../v1alpha1/trigger_validation_test.go | 44 ++++++------------- 3 files changed, 34 insertions(+), 34 deletions(-) create mode 100644 pkg/apis/eventing/v1alpha1/broker_validation_test.go diff --git a/pkg/apis/eventing/v1alpha1/broker_validation_test.go b/pkg/apis/eventing/v1alpha1/broker_validation_test.go new file mode 100644 index 00000000000..833cf12f577 --- /dev/null +++ b/pkg/apis/eventing/v1alpha1/broker_validation_test.go @@ -0,0 +1,17 @@ +/* +Copyright 2019 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 diff --git a/pkg/apis/eventing/v1alpha1/trigger_validation.go b/pkg/apis/eventing/v1alpha1/trigger_validation.go index e58150fdf48..ae57a5bf4e6 100644 --- a/pkg/apis/eventing/v1alpha1/trigger_validation.go +++ b/pkg/apis/eventing/v1alpha1/trigger_validation.go @@ -53,13 +53,14 @@ func (ts *TriggerSpec) Validate() *apis.FieldError { } func (t *Trigger) CheckImmutableFields(og apis.Immutable) *apis.FieldError { + if og == nil { + return nil + } + original, ok := og.(*Trigger) if !ok { return &apis.FieldError{Message: "The provided original was not a Trigger"} } - if original == nil { - return nil - } if diff := cmp.Diff(original.Spec.Broker, t.Spec.Broker); diff != "" { return &apis.FieldError{ diff --git a/pkg/apis/eventing/v1alpha1/trigger_validation_test.go b/pkg/apis/eventing/v1alpha1/trigger_validation_test.go index 8afa183faca..313f8132708 100644 --- a/pkg/apis/eventing/v1alpha1/trigger_validation_test.go +++ b/pkg/apis/eventing/v1alpha1/trigger_validation_test.go @@ -144,8 +144,8 @@ func TestTriggerSpecValidation(t *testing.T) { func TestTriggerImmutableFields(t *testing.T) { tests := []struct { name string - current *Trigger - original *Trigger + current apis.Immutable + original apis.Immutable want *apis.FieldError }{{ name: "good (no change)", @@ -169,6 +169,17 @@ func TestTriggerImmutableFields(t *testing.T) { }, original: nil, want: nil, + }, { + name: "invalid type", + current: &Trigger{ + Spec: TriggerSpec{ + Broker: "broker", + }, + }, + original: &Broker{}, + want: &apis.FieldError{ + Message: "The provided original was not a Trigger", + }, }, { name: "good (filter change)", current: &Trigger{ @@ -214,32 +225,3 @@ func TestTriggerImmutableFields(t *testing.T) { }) } } - -func TestTriggerInvalidImmutableType(t *testing.T) { - tests := []struct { - name string - current apis.Immutable - original apis.Immutable - want *apis.FieldError - }{{ - name: "invalid type", - current: &Trigger{ - Spec: TriggerSpec{ - Broker: "broker", - }, - }, - original: nil, - want: &apis.FieldError{ - Message: "The provided original was not a Trigger", - }, - }} - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - got := test.current.CheckImmutableFields(test.original) - if diff := cmp.Diff(test.want.Error(), got.Error()); diff != "" { - t.Errorf("CheckImmutableType (-want, +got) = %v", diff) - } - }) - } -} From d713eeb3dd17f10acc2e5813245b8112bf48db86 Mon Sep 17 00:00:00 2001 From: nachocano Date: Tue, 19 Feb 2019 11:52:03 -0800 Subject: [PATCH 066/221] Adding dummy tests for broker validation... Should be implemented --- .../eventing/v1alpha1/broker_validation.go | 2 ++ .../v1alpha1/broker_validation_test.go | 23 +++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/pkg/apis/eventing/v1alpha1/broker_validation.go b/pkg/apis/eventing/v1alpha1/broker_validation.go index 028b8db11f6..3dbe58255b5 100644 --- a/pkg/apis/eventing/v1alpha1/broker_validation.go +++ b/pkg/apis/eventing/v1alpha1/broker_validation.go @@ -25,9 +25,11 @@ func (b *Broker) Validate() *apis.FieldError { } func (bs *BrokerSpec) Validate() *apis.FieldError { + // TODO implement return nil } func (b *Broker) CheckImmutableFields(og apis.Immutable) *apis.FieldError { + // TODO implement return nil } diff --git a/pkg/apis/eventing/v1alpha1/broker_validation_test.go b/pkg/apis/eventing/v1alpha1/broker_validation_test.go index 833cf12f577..b7842e869bb 100644 --- a/pkg/apis/eventing/v1alpha1/broker_validation_test.go +++ b/pkg/apis/eventing/v1alpha1/broker_validation_test.go @@ -15,3 +15,26 @@ limitations under the License. */ package v1alpha1 + +import ( + "testing" +) + +// No-op test because method does nothing. +func TestBrokerValidation(t *testing.T) { + b := Broker{} + _ = b.Validate() +} + +// No-op test because method does nothing. +func TestBrokerSpecValidation(t *testing.T) { + bs := BrokerSpec{} + _ = bs.Validate() +} + +// No-op test because method does nothing. +func TestBrokerImmutableFields(t *testing.T) { + original := &Broker{} + current := &Broker{} + _ = current.CheckImmutableFields(original) +} From 49fd1a0ac57ba5589535639132d8d0786011a7a4 Mon Sep 17 00:00:00 2001 From: nachocano Date: Tue, 19 Feb 2019 15:06:16 -0800 Subject: [PATCH 067/221] Compiling and moving things around --- ..._filter_test.go => broker_trigger_test.go} | 90 +++++++------------ test/e2e/builder/broker.go | 48 ---------- test/e2e/{builder/trigger.go => builders.go} | 55 ++++++++++-- test/e2e/e2e.go | 40 +++++++++ test/e2e/fixtures.go | 13 +-- test/e2e/single_event_test.go | 45 +--------- test/states.go | 4 +- 7 files changed, 128 insertions(+), 167 deletions(-) rename test/e2e/{broker_filter_test.go => broker_trigger_test.go} (70%) delete mode 100644 test/e2e/builder/broker.go rename test/e2e/{builder/trigger.go => builders.go} (60%) diff --git a/test/e2e/broker_filter_test.go b/test/e2e/broker_trigger_test.go similarity index 70% rename from test/e2e/broker_filter_test.go rename to test/e2e/broker_trigger_test.go index f42436dae2b..905c1d6083b 100644 --- a/test/e2e/broker_filter_test.go +++ b/test/e2e/broker_trigger_test.go @@ -18,15 +18,14 @@ limitations under the License. package e2e import ( + "context" "fmt" "testing" - "time" "github.com/knative/eventing/test" + "github.com/knative/eventing/test/e2e/broker_trigger/builder" pkgTest "github.com/knative/pkg/test" "github.com/knative/pkg/test/logging" - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/uuid" ) @@ -34,62 +33,24 @@ import ( const ( defaultBrokerName = "default" altBrokerName = "alternate" - anyEvent = "Any" untypedEvent = "test.untyped" typedEvent = "test.typed" + unsourcedEvent = "test.unsourced" + sourcedEvent = "test.sourced" ) func triggerName(broker, eventType string) string { fmt.Sprintf("%s-dump-%s", broker, eventType) } -func namespaceExists(t *testing.T, clients *test.Clients) (string, func()) { - logger := logging.GetContextLogger("TestBrokerFilter") - shutdown := func() {} - ns := pkgTest.Flags.Namespace - logger.Infof("Namespace: %s", ns) - - nsSpec, err := clients.Kube.Kube.CoreV1().Namespaces().Get(ns, metav1.GetOptions{}) - - if err != nil && errors.IsNotFound(err) { - nsSpec = &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: ns}} - logger.Infof("Creating Namespace: %s", ns) - nsSpec, err = clients.Kube.Kube.CoreV1().Namespaces().Create(nsSpec) - if err != nil { - t.Fatalf("Failed to create Namespace: %s; %v", ns, err) - } else { - shutdown = func() { - clients.Kube.Kube.CoreV1().Namespaces().Delete(nsSpec.Name, nil) - // TODO: this is a bit hacky but in order for the tests to work - // correctly for a clean namespace to be created we need to also - // wait for it to be removed. - // To fix this we could generate namespace names. - // This only happens when the namespace provided does not exist. - // - // wait up to 120 seconds for the namespace to be removed. - logger.Infof("Deleting Namespace: %s", ns) - for i := 0; i < 120; i++ { - time.Sleep(1 * time.Second) - if _, err := clients.Kube.Kube.CoreV1().Namespaces().Get(ns, metav1.GetOptions{}); err != nil && errors.IsNotFound(err) { - logger.Info("Namespace has been deleted") - // the namespace is gone. - break - } - } - } - } - } - return ns, shutdown -} - -func TestBrokerFilter(t *testing.T) { - logger := logging.GetContextLogger("TestBrokerFilter") +func TestBrokerTrigger(t *testing.T) { + logger := logging.GetContextLogger("TestBrokerTrigger") clients, cleaner := Setup(t, logger) defer TearDown(clients, cleaner, logger) // verify namespace - ns, cleanupNS := namespaceExists(t, clients) + ns, cleanupNS := NamespaceExists(t, clients, logger) defer cleanupNS() // Fixtures @@ -99,16 +60,21 @@ func TestBrokerFilter(t *testing.T) { fixtures := []Fixture{ // Default Any Trigger &KnativeFixture{ - Object: builder.Trigger("default-dump-any"), pkgTest.Flags.Namespace). - Type(anyEvent). + Object: builder.Trigger("default-dump-any", pkgTest.Flags.Namespace). SubscriberSvc("default-any-dumper"), }, // Default Typed Trigger &KnativeFixture{ - Object: builder.Trigger("default-dump-typed"), pkgTest.Flags.Namespace). + Object: builder.Trigger("default-dump-typed", pkgTest.Flags.Namespace). Type(typedEvent). SubscriberSvc("default-typed-dumper"), }, + // Default Sourced Trigger + &KnativeFixture{ + Object: builder.Trigger("default-dump-sourced", pkgTest.Flags.Namespace). + Type(sourcedEvent). + SubscriberSvc("default-sourced-dumper"), + }, // Alternate Broker &KnativeFixture{ @@ -116,18 +82,24 @@ func TestBrokerFilter(t *testing.T) { }, // Alternate Any Trigger &KnativeFixture{ - Object: builder.Trigger("alt-dump-any"), pkgTest.Flags.Namespace). + Object: builder.Trigger("alt-dump-any", pkgTest.Flags.Namespace). Broker(altBrokerName). - Type(anyEvent). - SubscriberSvc(fmt.Sprintf("alt-any-dumper"), + SubscriberSvc(fmt.Sprintf("alt-any-dumper")), }, // Alternate Typed Trigger &KnativeFixture{ - Object: builder.Trigger("alt-dump-typed"), pkgTest.Flags.Namespace). + Object: builder.Trigger("alt-dump-typed", pkgTest.Flags.Namespace). Broker(altBrokerName). Type(typedEvent). SubscriberSvc("alt-typed-dumper"), }, + // Alternate Sourced Trigger + &KnativeFixture{ + Object: builder.Trigger("alt-dump-sourced", pkgTest.Flags.Namespace). + Broker(altBrokerName). + Type(sourcedEvent). + SubscriberSvc("alt-sourced-dumper"), + }, } ctx := context.Background() @@ -145,13 +117,13 @@ func TestBrokerFilter(t *testing.T) { // Create message dumper services // Create: pod // Verify: pod status is ready - // + // - pods := []Fixture{ - &PodSuccess{ - - } - } + //pods := []Fixture{ + // &PodSuccess{ + // + // } + //} // create alt Broker diff --git a/test/e2e/builder/broker.go b/test/e2e/builder/broker.go deleted file mode 100644 index dc00c6245d3..00000000000 --- a/test/e2e/builder/broker.go +++ /dev/null @@ -1,48 +0,0 @@ -/* -Copyright 2019 The Knative Authors -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT 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 builder - -import ( - eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" -) - -type BrokerBuilder struct { - *eventingv1alpha1.Broker -} - -func Broker(name, namespace string) *BrokerBuilder { - broker := &eventingv1alpha1.Broker{ - TypeMeta: metav1.TypeMeta{ - APIVersion: eventingv1alpha1.SchemeGroupVersion.String(), - Kind: "Broker", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: namespace, - }, - Spec: eventingv1alpha1.BrokerSpec{}, - } - - return &BrokerBuilder{ - Broker: broker, - } -} - -func (b *BrokerBuilder) Build() runtime.Object { - return b.Broker.DeepCopy() -} \ No newline at end of file diff --git a/test/e2e/builder/trigger.go b/test/e2e/builders.go similarity index 60% rename from test/e2e/builder/trigger.go rename to test/e2e/builders.go index 745a71a34ad..ae1853fbbb1 100644 --- a/test/e2e/builder/trigger.go +++ b/test/e2e/builders.go @@ -13,7 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package builder +package e2e import ( eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" @@ -22,6 +22,34 @@ import ( "k8s.io/apimachinery/pkg/runtime" ) +// Broker builder. +type BrokerBuilder struct { + *eventingv1alpha1.Broker +} + +func Broker(name, namespace string) *BrokerBuilder { + broker := &eventingv1alpha1.Broker{ + TypeMeta: metav1.TypeMeta{ + APIVersion: eventingv1alpha1.SchemeGroupVersion.String(), + Kind: "Broker", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + }, + Spec: eventingv1alpha1.BrokerSpec{}, + } + + return &BrokerBuilder{ + Broker: broker, + } +} + +func (b *BrokerBuilder) Build() runtime.Object { + return b.Broker.DeepCopy() +} + +// Trigger builder. type TriggerBuilder struct { *eventingv1alpha1.Trigger } @@ -36,7 +64,15 @@ func Trigger(name, namespace string) *TriggerBuilder { Name: name, Namespace: namespace, }, - Spec: eventingv1alpha1.TriggerSpec{}, + Spec: eventingv1alpha1.TriggerSpec{ + Filter: &eventingv1alpha1.TriggerFilter{ + // Create a Any filter by default. + SourceAndType: &eventingv1alpha1.TriggerFilterSourceAndType{ + Source: eventingv1alpha1.TriggerAnyFilter, + Type: eventingv1alpha1.TriggerAnyFilter, + }, + }, + }, } return &TriggerBuilder{ @@ -49,7 +85,12 @@ func (b *TriggerBuilder) Build() runtime.Object { } func (b *TriggerBuilder) Type(eventType string) *TriggerBuilder { - b.Trigger.Spec.Type = eventType + b.Trigger.Spec.Filter.SourceAndType.Type = eventType + return b +} + +func (b *TriggerBuilder) Source(eventSource string) *TriggerBuilder { + b.Trigger.Spec.Filter.SourceAndType.Source = eventSource return b } @@ -66,9 +107,9 @@ func (b *TriggerBuilder) Subscriber(ref *corev1.ObjectReference) *TriggerBuilder func (b *TriggerBuilder) SubscriberSvc(svcName string) *TriggerBuilder { b.Trigger.Spec.Subscriber.Ref = &corev1.ObjectReference{ APIVersion: corev1.SchemeGroupVersion.String(), - Kind: "Service", - Name: svcName, - Namespace: b.Trigger.GetNamespace(), + Kind: "Service", + Name: svcName, + Namespace: b.Trigger.GetNamespace(), } return b -} \ No newline at end of file +} diff --git a/test/e2e/e2e.go b/test/e2e/e2e.go index 453c0c69ea6..5fd3fffd4c3 100644 --- a/test/e2e/e2e.go +++ b/test/e2e/e2e.go @@ -21,6 +21,8 @@ import ( "testing" "time" + "k8s.io/apimachinery/pkg/api/errors" + "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" "github.com/knative/eventing/test" pkgTest "github.com/knative/pkg/test" @@ -305,3 +307,41 @@ func WaitForAllPodsRunning(clients *test.Clients, logger *logging.BaseLogger, na } return nil } + +func NamespaceExists(t *testing.T, clients *test.Clients, logger *logging.BaseLogger) (string, func()) { + shutdown := func() {} + ns := pkgTest.Flags.Namespace + logger.Infof("Namespace: %s", ns) + + nsSpec, err := clients.Kube.Kube.CoreV1().Namespaces().Get(ns, metav1.GetOptions{}) + + if err != nil && errors.IsNotFound(err) { + nsSpec = &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: ns}} + logger.Infof("Creating Namespace: %s", ns) + nsSpec, err = clients.Kube.Kube.CoreV1().Namespaces().Create(nsSpec) + if err != nil { + t.Fatalf("Failed to create Namespace: %s; %v", ns, err) + } else { + shutdown = func() { + clients.Kube.Kube.CoreV1().Namespaces().Delete(nsSpec.Name, nil) + // TODO: this is a bit hacky but in order for the tests to work + // correctly for a clean namespace to be created we need to also + // wait for it to be removed. + // To fix this we could generate namespace names. + // This only happens when the namespace provided does not exist. + // + // wait up to 120 seconds for the namespace to be removed. + logger.Infof("Deleting Namespace: %s", ns) + for i := 0; i < 120; i++ { + time.Sleep(1 * time.Second) + if _, err := clients.Kube.Kube.CoreV1().Namespaces().Get(ns, metav1.GetOptions{}); err != nil && errors.IsNotFound(err) { + logger.Info("Namespace has been deleted") + // the namespace is gone. + break + } + } + } + } + } + return ns, shutdown +} diff --git a/test/e2e/fixtures.go b/test/e2e/fixtures.go index f2174c58048..3bfa969bd7d 100644 --- a/test/e2e/fixtures.go +++ b/test/e2e/fixtures.go @@ -16,6 +16,7 @@ package e2e import ( "context" + "github.com/knative/eventing/pkg/reconciler/testing" "github.com/knative/pkg/apis/duck" duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" @@ -41,7 +42,7 @@ type Fixture interface { } type KnativeFixture struct { - Object testing.Buildable + Object testing.Buildable } type CreateFunc func(context.Context, client.Client) error @@ -50,9 +51,9 @@ type DebugFunc func(context.Context, client.Client) type TeardownFunc func(context.Context, client.Client) error type FixtureFuncs struct { - Create CreateFunc - Verify VerifyFunc - Debug DebugFunc + Create CreateFunc + Verify VerifyFunc + Debug DebugFunc Teardown TeardownFunc } @@ -102,7 +103,7 @@ func (f *KnativeFixture) Debug(ctx context.Context, cl client.Client) { } // TODO if Teardown returns an error, log it and give up (maybe retry for a while?) -func (f *KnativeFixture) Teardownctx context.Context, cl client.Client) error { +func (f *KnativeFixture) Teardown(ctx context.Context, cl client.Client) error { obj := f.Object.Build() return cl.Delete(ctx, obj) -} \ No newline at end of file +} diff --git a/test/e2e/single_event_test.go b/test/e2e/single_event_test.go index f62f2bab46d..a1d9455c71d 100644 --- a/test/e2e/single_event_test.go +++ b/test/e2e/single_event_test.go @@ -20,13 +20,9 @@ package e2e import ( "fmt" "testing" - "time" "github.com/knative/eventing/test" - pkgTest "github.com/knative/pkg/test" "github.com/knative/pkg/test/logging" - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/uuid" ) @@ -39,45 +35,6 @@ const ( routeName = "e2e-singleevent-route" ) -func namespaceExists(t *testing.T, clients *test.Clients) (string, func()) { - logger := logging.GetContextLogger("TestSingleEvent") - shutdown := func() {} - ns := pkgTest.Flags.Namespace - logger.Infof("Namespace: %s", ns) - - nsSpec, err := clients.Kube.Kube.CoreV1().Namespaces().Get(ns, metav1.GetOptions{}) - - if err != nil && errors.IsNotFound(err) { - nsSpec = &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: ns}} - logger.Infof("Creating Namespace: %s", ns) - nsSpec, err = clients.Kube.Kube.CoreV1().Namespaces().Create(nsSpec) - if err != nil { - t.Fatalf("Failed to create Namespace: %s; %v", ns, err) - } else { - shutdown = func() { - clients.Kube.Kube.CoreV1().Namespaces().Delete(nsSpec.Name, nil) - // TODO: this is a bit hacky but in order for the tests to work - // correctly for a clean namespace to be created we need to also - // wait for it to be removed. - // To fix this we could generate namespace names. - // This only happens when the namespace provided does not exist. - // - // wait up to 120 seconds for the namespace to be removed. - logger.Infof("Deleting Namespace: %s", ns) - for i := 0; i < 120; i++ { - time.Sleep(1 * time.Second) - if _, err := clients.Kube.Kube.CoreV1().Namespaces().Get(ns, metav1.GetOptions{}); err != nil && errors.IsNotFound(err) { - logger.Info("Namespace has been deleted") - // the namespace is gone. - break - } - } - } - } - } - return ns, shutdown -} - func TestSingleBinaryEvent(t *testing.T) { SingleEvent(t, test.CloudEventEncodingBinary) } @@ -94,7 +51,7 @@ func SingleEvent(t *testing.T, encoding string) { // verify namespace - ns, cleanupNS := namespaceExists(t, clients) + ns, cleanupNS := NamespaceExists(t, clients, logger) defer cleanupNS() // create logger pod diff --git a/test/states.go b/test/states.go index e5a8dd0cdcf..26db82aee3d 100644 --- a/test/states.go +++ b/test/states.go @@ -54,7 +54,7 @@ func IsSubscriptionReady(s *eventingv1alpha1.Subscription) (bool, error) { return s.Status.IsReady(), nil } -/ IsBrokerReady will check the status conditions of the Broker and return true +// IsBrokerReady will check the status conditions of the Broker and return true // if the Broker is ready. func IsBrokerReady(b *eventingv1alpha1.Broker) (bool, error) { return b.Status.IsReady(), nil @@ -66,8 +66,6 @@ func IsTriggerReady(t *eventingv1alpha1.Trigger) (bool, error) { return t.Status.IsReady(), nil } - - // PodsRunning will check the status conditions of the pod list and return true // if all pods are Running. func PodsRunning(podList *corev1.PodList) (bool, error) { From 4cdfd5888b86042b406d347d4f5d7f7aea8e0a43 Mon Sep 17 00:00:00 2001 From: nachocano Date: Tue, 19 Feb 2019 18:04:18 -0800 Subject: [PATCH 068/221] Updating test --- test/crd.go | 19 ++- test/e2e/broker_trigger_test.go | 203 +++++++++++--------------------- test/e2e/builders.go | 45 +++---- test/e2e/e2e.go | 20 ++++ 4 files changed, 128 insertions(+), 159 deletions(-) diff --git a/test/crd.go b/test/crd.go index 0806b221a70..f9f350e5939 100644 --- a/test/crd.go +++ b/test/crd.go @@ -19,6 +19,7 @@ package test import ( "fmt" + "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" servingv1alpha1 "github.com/knative/serving/pkg/apis/serving/v1alpha1" corev1 "k8s.io/api/core/v1" @@ -167,6 +168,7 @@ func Subscription(name string, namespace string, channel *corev1.ObjectReference } } +// Broker returns a Broker. func Broker(name string, namespace string) *v1alpha1.Broker { return &v1alpha1.Broker{ ObjectMeta: metav1.ObjectMeta{ @@ -177,7 +179,8 @@ func Broker(name string, namespace string) *v1alpha1.Broker { } } -func Trigger(name string, namespace string, eventType string, subscriberRef *corev1.ObjectReference, brokerName string) *v1alpha1.Trigger { +// Trigger returns a Trigger. +func Trigger(name, namespace, eventType, eventSource, brokerName, svcName string) *v1alpha1.Trigger { return &v1alpha1.Trigger{ ObjectMeta: metav1.ObjectMeta{ Name: name, @@ -185,9 +188,19 @@ func Trigger(name string, namespace string, eventType string, subscriberRef *cor }, Spec: v1alpha1.TriggerSpec{ Broker: brokerName, - Type: fmt.Sprintf("%q", eventType), + Filter: &v1alpha1.TriggerFilter{ + SourceAndType: &v1alpha1.TriggerFilterSourceAndType{ + Type: fmt.Sprintf("%q", eventType), + Source: fmt.Sprintf("%q", eventSource), + }, + }, Subscriber: &v1alpha1.SubscriberSpec{ - Ref: subscriberRef, + Ref: &corev1.ObjectReference{ + APIVersion: corev1.SchemeGroupVersion.String(), + Kind: "Service", + Name: svcName, + Namespace: namespace, + }, }, }, } diff --git a/test/e2e/broker_trigger_test.go b/test/e2e/broker_trigger_test.go index 905c1d6083b..cfbb94408ee 100644 --- a/test/e2e/broker_trigger_test.go +++ b/test/e2e/broker_trigger_test.go @@ -18,27 +18,35 @@ limitations under the License. package e2e import ( - "context" "fmt" "testing" + "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" + "github.com/knative/eventing/test" - "github.com/knative/eventing/test/e2e/broker_trigger/builder" - pkgTest "github.com/knative/pkg/test" "github.com/knative/pkg/test/logging" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/uuid" ) const ( defaultBrokerName = "default" - altBrokerName = "alternate" - untypedEvent = "test.untyped" - typedEvent = "test.typed" - unsourcedEvent = "test.unsourced" - sourcedEvent = "test.sourced" + + eventAny = v1alpha1.TriggerAnyFilter + eventType1 = "test.type1" + eventType2 = "test.type2" + eventSource1 = "test.source1" + eventSource2 = "test.source2" + + defaultAnyDumper = "default-any-dumper" + defaultType1Dumper = "default-type1-dumper" + defaultSource1Dumper = "default-source1-dumper" + defaultType1Source1Dumper = "default-type1-source1-dumper" ) +type TypeAndSource struct { + Type, Source string +} + func triggerName(broker, eventType string) string { fmt.Sprintf("%s-dump-%s", broker, eventType) } @@ -53,151 +61,78 @@ func TestBrokerTrigger(t *testing.T) { ns, cleanupNS := NamespaceExists(t, clients, logger) defer cleanupNS() - // Fixtures - // TODO label namespace to get default Broker - fixtures := []Fixture{ - // Default Any Trigger - &KnativeFixture{ - Object: builder.Trigger("default-dump-any", pkgTest.Flags.Namespace). - SubscriberSvc("default-any-dumper"), - }, - // Default Typed Trigger - &KnativeFixture{ - Object: builder.Trigger("default-dump-typed", pkgTest.Flags.Namespace). - Type(typedEvent). - SubscriberSvc("default-typed-dumper"), - }, - // Default Sourced Trigger - &KnativeFixture{ - Object: builder.Trigger("default-dump-sourced", pkgTest.Flags.Namespace). - Type(sourcedEvent). - SubscriberSvc("default-sourced-dumper"), - }, - - // Alternate Broker - &KnativeFixture{ - Object: builder.Broker(altBrokerName, pkgTest.Flags.Namespace), - }, - // Alternate Any Trigger - &KnativeFixture{ - Object: builder.Trigger("alt-dump-any", pkgTest.Flags.Namespace). - Broker(altBrokerName). - SubscriberSvc(fmt.Sprintf("alt-any-dumper")), - }, - // Alternate Typed Trigger - &KnativeFixture{ - Object: builder.Trigger("alt-dump-typed", pkgTest.Flags.Namespace). - Broker(altBrokerName). - Type(typedEvent). - SubscriberSvc("alt-typed-dumper"), - }, - // Alternate Sourced Trigger - &KnativeFixture{ - Object: builder.Trigger("alt-dump-sourced", pkgTest.Flags.Namespace). - Broker(altBrokerName). - Type(sourcedEvent). - SubscriberSvc("alt-sourced-dumper"), - }, - } + logger.Info("Creating Subscriber pods") - ctx := context.Background() + eventLoggerSelectors := []map[string]string{{"svcName": defaultAnyDumper}, {"svcName": defaultType1Dumper}, {"svcName": defaultSource1Dumper}, {"svcName": defaultType1Source1Dumper}} - //TODO move this to runners + for eventLoggerSelector := range eventLoggerSelectors { + subscriberPod := test.EventLoggerPod(eventLoggerSelector["svcName"], ns, eventLoggerSelector) - for _, f := range fixtures { - f.Create(ctx, client) + if err := CreatePod(clients, subscriberPod, logger, cleaner); err != nil { + t.Fatalf("Failed to create event logger pod: %v", err) + } } - for _, f := range fixtures { - f.Verify(ctx, client) + if err := WaitForAllPodsRunning(clients, logger, ns); err != nil { + t.Fatalf("Error waiting for event logger pod to become running: %v", err) } - // Create message dumper services - // Create: pod - // Verify: pod status is ready - // - - //pods := []Fixture{ - // &PodSuccess{ - // - // } - //} - - // create alt Broker - - // For each broker, create a typed and untyped trigger. - // For each trigger, create a logevents pod. - // Wait for Broker, triggers, and pods to become ready. - - // Take Action + logger.Info("Subscriber pods running") - // For each tuple of typed and untyped, default and alt broker: - // create a sendevents pod to send an event of the type to the broker address - - // Verify - - // For each logevents pod: - // check logs to ensure the correct message(s) got there + for eventLoggerSelector := range eventLoggerSelectors { + subscriberSvc := test.Service(eventLoggerSelector["svcName"], ns, eventLoggerSelector) + if err := CreateService(clients, subscriberSvc, logger, cleaner); err != nil { + t.Fatalf("Failed to create event logger service: %v", err) + } + } - // create logger pod + logger.Info("Creating Triggers") - logger.Infof("creating subscriber pod") - selector := map[string]string{"e2etest": string(uuid.NewUUID())} - subscriberPod := test.EventLoggerPod(routeName, ns, selector) - if err := CreatePod(clients, subscriberPod, logger, cleaner); err != nil { - t.Fatalf("Failed to create event logger pod: %v", err) + defaultTriggers := []*v1alpha1.Trigger{ + test.Trigger("default-dump-any", ns, eventAny, eventAny, defaultBrokerName, defaultAnyDumper), + test.Trigger("default-dump-type1", ns, eventType1, eventAny, defaultBrokerName, defaultType1Dumper), + test.Trigger("default-dump-source1", ns, eventAny, eventSource1, defaultBrokerName, defaultSource1Dumper), + test.Trigger("default-dump-type1-source1", ns, eventType1, eventSource1, defaultBrokerName, defaultType1Source1Dumper), } - if err := WaitForAllPodsRunning(clients, logger, ns); err != nil { - t.Fatalf("Error waiting for logger pod to become running: %v", err) - } - logger.Infof("subscriber pod running") - - subscriberSvc := test.Service(routeName, ns, selector) - if err := CreateService(clients, subscriberSvc, logger, cleaner); err != nil { - t.Fatalf("Failed to create event logger service: %v", err) + for defaultTrigger := range defaultTriggers { + err := WithTriggerReady(clients, defaultTrigger, logger, cleaner) + if err != nil { + t.Fatalf("Error waiting for default trigger to become ready: %v", err) + } } - // Reload subscriberPod to get IP - subscriberPod, err := clients.Kube.Kube.CoreV1().Pods(subscriberPod.Namespace).Get(subscriberPod.Name, metav1.GetOptions{}) - if err != nil { - t.Fatalf("Failed to get subscriber pod: %v", err) - } + logger.Info("Triggers ready") - // create channel + logger.Infof("Creating event sender pods") - logger.Infof("Creating Channel and Subscription") - if test.EventingFlags.Provisioner == "" { - t.Fatal("ClusterChannelProvisioner must be set to a non-empty string. Either do not specify --clusterChannelProvisioner or set to something other than the empty string") + events = []TypeAndSource{ + {eventType1, eventSource1}, + {eventType1, eventSource2}, + {eventType2, eventSource1}, + {eventType2, eventSource2}, } - channel := test.Channel(channelName, ns, test.ClusterChannelProvisioner(test.EventingFlags.Provisioner)) - logger.Infof("channel: %#v", channel) - sub := test.Subscription(subscriptionName, ns, test.ChannelRef(channelName), test.SubscriberSpecForService(routeName), nil) - logger.Infof("sub: %#v", sub) - if err := WithChannelAndSubscriptionReady(clients, channel, sub, logger, cleaner); err != nil { - t.Fatalf("The Channel or Subscription were not marked as Ready: %v", err) + for event := range events { + body := fmt.Sprintf("Testing Broker-Trigger %s", uuid.NewUUID()) + cloudEvent := test.CloudEvent{ + Source: event.Source, + Type: event.Type, + Data: fmt.Sprintf(`{"msg":%q}`, body), + Encoding: encoding, + } + url := fmt.Sprintf("http://%s", channel.Status.Address.Hostname) + senderPod := test.EventSenderPod(event.Source, ns, url, cloudEvent) + logger.Infof("Sender pod: %#v", senderPod) + if err := CreatePod(clients, senderPod, logger, cleaner); err != nil { + t.Fatalf("Failed to create event sender pod: %v", err) + } } - // create sender pod - - logger.Infof("Creating event sender") - body := fmt.Sprintf("TestSingleEvent %s", uuid.NewUUID()) - event := test.CloudEvent{ - Source: senderName, - Type: "test.eventing.knative.dev", - Data: fmt.Sprintf(`{"msg":%q}`, body), - Encoding: encoding, - } - url := fmt.Sprintf("http://%s", channel.Status.Address.Hostname) - pod := test.EventSenderPod(senderName, ns, url, event) - logger.Infof("sender pod: %#v", pod) - if err := CreatePod(clients, pod, logger, cleaner); err != nil { - t.Fatalf("Failed to create event sender pod: %v", err) - } + // Verify that each arrived to its own place. + //if err := WaitForLogContent(clients, logger, routeName, subscriberPod.Spec.Containers[0].Name, ns, body); err != nil { + // t.Fatalf("String %q not found in logs of subscriber pod %q: %v", body, routeName, err) + //} - if err := WaitForLogContent(clients, logger, routeName, subscriberPod.Spec.Containers[0].Name, ns, body); err != nil { - t.Fatalf("String %q not found in logs of subscriber pod %q: %v", body, routeName, err) - } } diff --git a/test/e2e/builders.go b/test/e2e/builders.go index ae1853fbbb1..e89bb26f0a2 100644 --- a/test/e2e/builders.go +++ b/test/e2e/builders.go @@ -19,7 +19,6 @@ import ( eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" ) // Broker builder. @@ -27,7 +26,7 @@ type BrokerBuilder struct { *eventingv1alpha1.Broker } -func Broker(name, namespace string) *BrokerBuilder { +func NewBrokerBuilder(name, namespace string) *BrokerBuilder { broker := &eventingv1alpha1.Broker{ TypeMeta: metav1.TypeMeta{ APIVersion: eventingv1alpha1.SchemeGroupVersion.String(), @@ -45,7 +44,7 @@ func Broker(name, namespace string) *BrokerBuilder { } } -func (b *BrokerBuilder) Build() runtime.Object { +func (b *BrokerBuilder) Build() *eventingv1alpha1.Broker { return b.Broker.DeepCopy() } @@ -54,7 +53,7 @@ type TriggerBuilder struct { *eventingv1alpha1.Trigger } -func Trigger(name, namespace string) *TriggerBuilder { +func NewTriggerBuilder(name, namespace string) *TriggerBuilder { trigger := &eventingv1alpha1.Trigger{ TypeMeta: metav1.TypeMeta{ APIVersion: eventingv1alpha1.SchemeGroupVersion.String(), @@ -65,6 +64,8 @@ func Trigger(name, namespace string) *TriggerBuilder { Namespace: namespace, }, Spec: eventingv1alpha1.TriggerSpec{ + // Bind to 'default' Broker by default + Broker: "default", Filter: &eventingv1alpha1.TriggerFilter{ // Create a Any filter by default. SourceAndType: &eventingv1alpha1.TriggerFilterSourceAndType{ @@ -80,36 +81,36 @@ func Trigger(name, namespace string) *TriggerBuilder { } } -func (b *TriggerBuilder) Build() runtime.Object { - return b.Trigger.DeepCopy() +func (t *TriggerBuilder) Build() *eventingv1alpha1.Trigger { + return t.Trigger.DeepCopy() } -func (b *TriggerBuilder) Type(eventType string) *TriggerBuilder { - b.Trigger.Spec.Filter.SourceAndType.Type = eventType - return b +func (t *TriggerBuilder) Type(eventType string) *TriggerBuilder { + t.Trigger.Spec.Filter.SourceAndType.Type = eventType + return t } -func (b *TriggerBuilder) Source(eventSource string) *TriggerBuilder { - b.Trigger.Spec.Filter.SourceAndType.Source = eventSource - return b +func (t *TriggerBuilder) Source(eventSource string) *TriggerBuilder { + t.Trigger.Spec.Filter.SourceAndType.Source = eventSource + return t } -func (b *TriggerBuilder) Broker(brokerName string) *TriggerBuilder { - b.Trigger.Spec.Broker = brokerName - return b +func (t *TriggerBuilder) Broker(brokerName string) *TriggerBuilder { + t.Trigger.Spec.Broker = brokerName + return t } -func (b *TriggerBuilder) Subscriber(ref *corev1.ObjectReference) *TriggerBuilder { - b.Trigger.Spec.Subscriber.Ref = ref - return b +func (t *TriggerBuilder) Subscriber(ref *corev1.ObjectReference) *TriggerBuilder { + t.Trigger.Spec.Subscriber.Ref = ref + return t } -func (b *TriggerBuilder) SubscriberSvc(svcName string) *TriggerBuilder { - b.Trigger.Spec.Subscriber.Ref = &corev1.ObjectReference{ +func (t *TriggerBuilder) SubscriberSvc(svcName string) *TriggerBuilder { + t.Trigger.Spec.Subscriber.Ref = &corev1.ObjectReference{ APIVersion: corev1.SchemeGroupVersion.String(), Kind: "Service", Name: svcName, - Namespace: b.Trigger.GetNamespace(), + Namespace: t.Trigger.GetNamespace(), } - return b + return t } diff --git a/test/e2e/e2e.go b/test/e2e/e2e.go index 5fd3fffd4c3..eedceab5ac1 100644 --- a/test/e2e/e2e.go +++ b/test/e2e/e2e.go @@ -183,6 +183,26 @@ func CreateTrigger(clients *test.Clients, trigger *v1alpha1.Trigger, logger *log return nil } +// WithTriggerReady creates a Trigger and waits until it is Ready. +func WithTriggerReady(clients *test.Clients, trigger *v1alpha1.Trigger, logger *logging.BaseLogger, cleaner *test.Cleaner) error { + if err := CreateTrigger(clients, trigger, logger, cleaner); err != nil { + return err + } + + triggers := clients.Eventing.EventingV1alpha1().Triggers(pkgTest.Flags.Namespace) + if err := test.WaitForTriggerState(triggers, trigger.Name, test.IsTriggerReady, "TriggerIsReady"); err != nil { + return err + } + // Update the given object so they'll reflect the ready state + updatedTrigger, err := triggers.Get(trigger.Name, metav1.GetOptions{}) + if err != nil { + return err + } + updatedTrigger.DeepCopyInto(trigger) + + return nil +} + // CreateServiceAccount will create a service account func CreateServiceAccount(clients *test.Clients, sa *corev1.ServiceAccount, logger *logging.BaseLogger, cleaner *test.Cleaner) error { sas := clients.Kube.Kube.CoreV1().ServiceAccounts(pkgTest.Flags.Namespace) From b42d359bbde96b0f184eb30a217790470ce2a025 Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Tue, 19 Feb 2019 23:58:33 -0800 Subject: [PATCH 069/221] More updates --- test/crd_checks.go | 22 ++++++++ test/e2e/broker_trigger_test.go | 91 ++++++++++++++++++--------------- test/e2e/e2e.go | 49 +++++++++++++++++- test/e2e/single_event_test.go | 2 +- 4 files changed, 120 insertions(+), 44 deletions(-) diff --git a/test/crd_checks.go b/test/crd_checks.go index f996b8e5fd0..6c66fc03ab9 100644 --- a/test/crd_checks.go +++ b/test/crd_checks.go @@ -23,6 +23,10 @@ import ( "fmt" "time" + v1 "k8s.io/client-go/kubernetes/typed/core/v1" + + corev1 "k8s.io/api/core/v1" + eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" eventingclient "github.com/knative/eventing/pkg/client/clientset/versioned/typed/eventing/v1alpha1" servingv1alpha1 "github.com/knative/serving/pkg/apis/serving/v1alpha1" @@ -127,3 +131,21 @@ func WaitForTriggerState(client eventingclient.TriggerInterface, name string, in return inState(r) }) } + +// WaitForServiceState polls the status of the Service called name from client +// every interval until inState returns `true` indicating it is done, returns an +// error or timeout. desc will be used to name the metric that is emitted to +// track how long it took for name to get into the state checked by inState. +func WaitForServiceState(client v1.ServiceInterface, name string, inState func(r *corev1.Service) (bool, error), desc string) error { + metricName := fmt.Sprintf("WaitForServiceState/%s/%s", name, desc) + _, span := trace.StartSpan(context.Background(), metricName) + defer span.End() + + return wait.PollImmediate(interval, timeout, func() (bool, error) { + r, err := client.Get(name, metav1.GetOptions{}) + if err != nil { + return true, err + } + return inState(r) + }) +} diff --git a/test/e2e/broker_trigger_test.go b/test/e2e/broker_trigger_test.go index cfbb94408ee..c5c8433c5f0 100644 --- a/test/e2e/broker_trigger_test.go +++ b/test/e2e/broker_trigger_test.go @@ -19,6 +19,7 @@ package e2e import ( "fmt" + "strings" "testing" "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" @@ -30,25 +31,21 @@ import ( const ( defaultBrokerName = "default" + selectorKey = "end2end-test-broker-trigger" - eventAny = v1alpha1.TriggerAnyFilter - eventType1 = "test.type1" - eventType2 = "test.type2" - eventSource1 = "test.source1" - eventSource2 = "test.source2" - - defaultAnyDumper = "default-any-dumper" - defaultType1Dumper = "default-type1-dumper" - defaultSource1Dumper = "default-source1-dumper" - defaultType1Source1Dumper = "default-type1-source1-dumper" + any = v1alpha1.TriggerAnyFilter + eventType1 = "type1" + eventType2 = "type2" + eventSource1 = "source1" + eventSource2 = "source2" ) type TypeAndSource struct { Type, Source string } -func triggerName(broker, eventType string) string { - fmt.Sprintf("%s-dump-%s", broker, eventType) +func name(brokerName, eventType, eventSource string) string { + return fmt.Sprintf("%s-%s-%s", brokerName, eventType, eventSource) } func TestBrokerTrigger(t *testing.T) { @@ -57,21 +54,30 @@ func TestBrokerTrigger(t *testing.T) { clients, cleaner := Setup(t, logger) defer TearDown(clients, cleaner, logger) - // verify namespace - ns, cleanupNS := NamespaceExists(t, clients, logger) + // verify namespace and annotate to create default broker + ns, cleanupNS := NamespaceExists(t, clients, logger, true) defer cleanupNS() - // TODO label namespace to get default Broker - - logger.Info("Creating Subscriber pods") + defaultBroker := test.Broker(defaultBrokerName, ns) + err := WaitForBrokerReady(clients, defaultBroker) + if err != nil { + t.Fatalf("Error waiting for default broker to become ready: %v", err) + } - eventLoggerSelectors := []map[string]string{{"svcName": defaultAnyDumper}, {"svcName": defaultType1Dumper}, {"svcName": defaultSource1Dumper}, {"svcName": defaultType1Source1Dumper}} + // name -> selector + eventLoggers := []map[string]map[string]string{ + {name(defaultBroker, any, any): {selectorKey: string(uuid.NewUUID())}}, + {name(defaultBroker, eventType1, any): {selectorKey: string(uuid.NewUUID())}}, + {name(defaultBroker, any, eventSource1): {selectorKey: string(uuid.NewUUID())}}, + {name(defaultBroker, eventType1, eventSource1): {selectorKey: string(uuid.NewUUID())}}, + } - for eventLoggerSelector := range eventLoggerSelectors { - subscriberPod := test.EventLoggerPod(eventLoggerSelector["svcName"], ns, eventLoggerSelector) + logger.Info("Creating Subscriber pods") + for name, selector := range eventLoggers { + subscriberPod := test.EventLoggerPod(name, ns, selector) if err := CreatePod(clients, subscriberPod, logger, cleaner); err != nil { - t.Fatalf("Failed to create event logger pod: %v", err) + t.Fatalf("Failed to create subscriber pod: %v", err) } } @@ -81,40 +87,41 @@ func TestBrokerTrigger(t *testing.T) { logger.Info("Subscriber pods running") - for eventLoggerSelector := range eventLoggerSelectors { - subscriberSvc := test.Service(eventLoggerSelector["svcName"], ns, eventLoggerSelector) - if err := CreateService(clients, subscriberSvc, logger, cleaner); err != nil { - t.Fatalf("Failed to create event logger service: %v", err) + logger.Info("Creating Subscriber services") + + for name, selector := range eventLoggers { + subscriberSvc := test.Service(name, ns, selector) + if err := WithServiceReady(clients, subscriberSvc, logger, cleaner); err != nil { + t.Fatalf("Error waiting for subscriber service to become ready: %v", err) } } + logger.Info("Subscriber services ready") + logger.Info("Creating Triggers") - defaultTriggers := []*v1alpha1.Trigger{ - test.Trigger("default-dump-any", ns, eventAny, eventAny, defaultBrokerName, defaultAnyDumper), - test.Trigger("default-dump-type1", ns, eventType1, eventAny, defaultBrokerName, defaultType1Dumper), - test.Trigger("default-dump-source1", ns, eventAny, eventSource1, defaultBrokerName, defaultSource1Dumper), - test.Trigger("default-dump-type1-source1", ns, eventType1, eventSource1, defaultBrokerName, defaultType1Source1Dumper), - } - for defaultTrigger := range defaultTriggers { + for name, selector := range eventLoggers { + strs := strings.Split(name, "-") + _, brokerName, eventType, eventSource := strs[0], strs[1], strs[2], strs[3] + trigger := test.Trigger(name, ns, eventType, eventSource, name) err := WithTriggerReady(clients, defaultTrigger, logger, cleaner) if err != nil { - t.Fatalf("Error waiting for default trigger to become ready: %v", err) + t.Fatalf("Error waiting for trigger to become ready: %v", err) } } logger.Info("Triggers ready") - logger.Infof("Creating event sender pods") - - events = []TypeAndSource{ + typesAndSources = []TypeAndSource{ {eventType1, eventSource1}, {eventType1, eventSource2}, {eventType2, eventSource1}, {eventType2, eventSource2}, } - for event := range events { + logger.Infof("Creating event sender pods") + // TODO should create a single pod that can send multiple events + for event := range typesAndSources { body := fmt.Sprintf("Testing Broker-Trigger %s", uuid.NewUUID()) cloudEvent := test.CloudEvent{ Source: event.Source, @@ -122,7 +129,7 @@ func TestBrokerTrigger(t *testing.T) { Data: fmt.Sprintf(`{"msg":%q}`, body), Encoding: encoding, } - url := fmt.Sprintf("http://%s", channel.Status.Address.Hostname) + url := fmt.Sprintf("http://%s", defaultBroker.Status.Address.Hostname) senderPod := test.EventSenderPod(event.Source, ns, url, cloudEvent) logger.Infof("Sender pod: %#v", senderPod) if err := CreatePod(clients, senderPod, logger, cleaner); err != nil { @@ -130,9 +137,9 @@ func TestBrokerTrigger(t *testing.T) { } } - // Verify that each arrived to its own place. - //if err := WaitForLogContent(clients, logger, routeName, subscriberPod.Spec.Containers[0].Name, ns, body); err != nil { - // t.Fatalf("String %q not found in logs of subscriber pod %q: %v", body, routeName, err) - //} + // Verify that each event arrived to its own place. + if err := WaitForLogContent(clients, logger, routeName, subscriberPod.Spec.Containers[0].Name, ns, body); err != nil { + t.Fatalf("String %q not found in logs of subscriber pod %q: %v", body, routeName, err) + } } diff --git a/test/e2e/e2e.go b/test/e2e/e2e.go index eedceab5ac1..756c161ccdd 100644 --- a/test/e2e/e2e.go +++ b/test/e2e/e2e.go @@ -172,6 +172,29 @@ func CreateBroker(clients *test.Clients, broker *v1alpha1.Broker, logger *loggin return nil } +// WithBrokerReady creates a Broker and waits until it is Ready. +func WithBrokerReady(clients *test.Clients, broker *v1alpha1.Broker, logger *logging.BaseLogger, cleaner *test.Cleaner) error { + if err := CreateBroker(clients, broker, logger, cleaner); err != nil { + return err + } + return WaitForBrokerReady(clients, broker) +} + +// WaitForBrokerReady waits until the broker is Ready. +func WaitForBrokerReady(clients *test.Clients, broker *v1alpha1.Broker) error { + brokers := clients.Eventing.EventingV1alpha1().Brokers(pkgTest.Flags.Namespace) + if err := test.WaitForBrokerState(brokers, broker.Name, test.IsBrokerReady, "BrokerIsReady"); err != nil { + return err + } + // Update the given object so they'll reflect the ready state + updatedBroker, err := brokers.Get(broker.Name, metav1.GetOptions{}) + if err != nil { + return err + } + updatedBroker.DeepCopyInto(broker) + return nil +} + // CreateTrigger will create a Trigger func CreateTrigger(clients *test.Clients, trigger *v1alpha1.Trigger, logger *logging.BaseLogger, cleaner *test.Cleaner) error { triggers := clients.Eventing.EventingV1alpha1().Triggers(pkgTest.Flags.Namespace) @@ -273,6 +296,26 @@ func CreateService(clients *test.Clients, svc *corev1.Service, logger *logging.B return nil } +// WithServiceReady creates a Service and waits until it is Ready. +func WithServiceReady(clients *test.Clients, svc *corev1.Service, logger *logging.BaseLogger, cleaner *test.Cleaner) error { + if err := CreateService(clients, svc, logger, cleaner); err != nil { + return err + } + + svcs := clients.Kube.Kube.CoreV1().Services(pkgTest.Flags.Namespace) + if err := test.WaitForServiceState(svcs, svc.Name, test.IsServiceReady, "ServiceIsReady"); err != nil { + return err + } + // Update the given object so they'll reflect the ready state + updatedSvc, err := svcs.Get(svc.Name, metav1.GetOptions{}) + if err != nil { + return err + } + updatedSvc.DeepCopyInto(svc) + + return nil +} + // CreatePod will create a Pod func CreatePod(clients *test.Clients, pod *corev1.Pod, logger *logging.BaseLogger, cleaner *test.Cleaner) error { pods := clients.Kube.Kube.CoreV1().Pods(pod.GetNamespace()) @@ -328,7 +371,7 @@ func WaitForAllPodsRunning(clients *test.Clients, logger *logging.BaseLogger, na return nil } -func NamespaceExists(t *testing.T, clients *test.Clients, logger *logging.BaseLogger) (string, func()) { +func NamespaceExists(t *testing.T, clients *test.Clients, logger *logging.BaseLogger, annotate bool) (string, func()) { shutdown := func() {} ns := pkgTest.Flags.Namespace logger.Infof("Namespace: %s", ns) @@ -337,8 +380,12 @@ func NamespaceExists(t *testing.T, clients *test.Clients, logger *logging.BaseLo if err != nil && errors.IsNotFound(err) { nsSpec = &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: ns}} + if annotate { + nsSpec.Annotations = map[string]string{"eventing.knative.dev/inject": "true"} + } logger.Infof("Creating Namespace: %s", ns) nsSpec, err = clients.Kube.Kube.CoreV1().Namespaces().Create(nsSpec) + if err != nil { t.Fatalf("Failed to create Namespace: %s; %v", ns, err) } else { diff --git a/test/e2e/single_event_test.go b/test/e2e/single_event_test.go index a1d9455c71d..8ccf04037fe 100644 --- a/test/e2e/single_event_test.go +++ b/test/e2e/single_event_test.go @@ -51,7 +51,7 @@ func SingleEvent(t *testing.T, encoding string) { // verify namespace - ns, cleanupNS := NamespaceExists(t, clients, logger) + ns, cleanupNS := NamespaceExists(t, clients, logger, false) defer cleanupNS() // create logger pod From 29be515f1974b26ca6d64f51fe505214889905f3 Mon Sep 17 00:00:00 2001 From: nachocano Date: Wed, 20 Feb 2019 11:04:28 -0800 Subject: [PATCH 070/221] Waiting for potentially multiple contents. Removing check for corev1.Service ready. Removing grant's great design. Just making it simpler for now. --- test/e2e/broker_trigger_test.go | 146 +++++++++++++++++++++++--------- test/e2e/builders.go | 116 ------------------------- test/e2e/e2e.go | 40 ++++----- test/e2e/fixtures.go | 109 ------------------------ 4 files changed, 120 insertions(+), 291 deletions(-) delete mode 100644 test/e2e/builders.go delete mode 100644 test/e2e/fixtures.go diff --git a/test/e2e/broker_trigger_test.go b/test/e2e/broker_trigger_test.go index c5c8433c5f0..bb7821d9187 100644 --- a/test/e2e/broker_trigger_test.go +++ b/test/e2e/broker_trigger_test.go @@ -19,13 +19,13 @@ package e2e import ( "fmt" - "strings" "testing" "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" "github.com/knative/eventing/test" "github.com/knative/pkg/test/logging" + corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/util/uuid" ) @@ -40,12 +40,29 @@ const ( eventSource2 = "source2" ) -type TypeAndSource struct { - Type, Source string +// Helper function to create names for different objects (e.g., triggers, services, etc.) +func name(obj, brokerName, eventType, eventSource string) string { + return fmt.Sprintf("%s-%s-%s-%s", obj, brokerName, eventType, eventSource) } -func name(brokerName, eventType, eventSource string) string { - return fmt.Sprintf("%s-%s-%s", brokerName, eventType, eventSource) +// Helper object to easily create subscriber pods, services and triggers. +// We also use this to verify the expected events that should be received +// by the particular subscriber pods. +type DumperInfo struct { + Namespace string + Broker string + EventType string + EventSource string + Selector map[string]string + ExpectedBodies []string +} + +// Helper object to easily create event sender pods. +type SenderInfo struct { + Namespace string + Url string + EventType string + EventSource string } func TestBrokerTrigger(t *testing.T) { @@ -54,33 +71,49 @@ func TestBrokerTrigger(t *testing.T) { clients, cleaner := Setup(t, logger) defer TearDown(clients, cleaner, logger) - // verify namespace and annotate to create default broker + // Verify namespace and annotate to create default broker. ns, cleanupNS := NamespaceExists(t, clients, logger, true) defer cleanupNS() + // Wait for default broker ready. defaultBroker := test.Broker(defaultBrokerName, ns) err := WaitForBrokerReady(clients, defaultBroker) if err != nil { t.Fatalf("Error waiting for default broker to become ready: %v", err) } - // name -> selector - eventLoggers := []map[string]map[string]string{ - {name(defaultBroker, any, any): {selectorKey: string(uuid.NewUUID())}}, - {name(defaultBroker, eventType1, any): {selectorKey: string(uuid.NewUUID())}}, - {name(defaultBroker, any, eventSource1): {selectorKey: string(uuid.NewUUID())}}, - {name(defaultBroker, eventType1, eventSource1): {selectorKey: string(uuid.NewUUID())}}, + defaultBrokerUrl := fmt.Sprintf("http://%s", defaultBroker.Status.Address.Hostname) + + // Create sender helpers. + senders := []SenderInfo{ + {ns, defaultBrokerUrl, eventType1, eventSource1}, + {ns, defaultBrokerUrl, eventType1, eventSource2}, + {ns, defaultBrokerUrl, eventType2, eventSource1}, + {ns, defaultBrokerUrl, eventType2, eventSource2}, + } + + // Create DumperInfo helpers. + dumpers := []DumperInfo{ + {ns, defaultBrokerName, any, any, {selectorKey: string(uuid.NewUUID())}, make([]string, 0)}, + {ns, defaultBrokerName, eventType1, any, {selectorKey: string(uuid.NewUUID())}, make([]string, 0)}, + {ns, defaultBrokerName, any, eventSource1, {selectorKey: string(uuid.NewUUID())}, make([]string, 0)}, + {ns, defaultBrokerName, eventType1, eventSource1, {selectorKey: string(uuid.NewUUID())}, make([]string, 0)}, } logger.Info("Creating Subscriber pods") - for name, selector := range eventLoggers { - subscriberPod := test.EventLoggerPod(name, ns, selector) + // Save the references in this map for later use. + subscriberPods := make(map[string]*corev1.Pod, 0) + for _, dumper := range dumpers { + subscriberPodName := name("dumper", dumper.Broker, dumper.EventType, dumper.EventSource) + subscriberPod := test.EventLoggerPod(subscriberPodName, dumper.Namespace, dumper.Selector) if err := CreatePod(clients, subscriberPod, logger, cleaner); err != nil { t.Fatalf("Failed to create subscriber pod: %v", err) } + subscriberPods[subscriberPodName] = subscriberPod } + // Wait for all of them to be running. if err := WaitForAllPodsRunning(clients, logger, ns); err != nil { t.Fatalf("Error waiting for event logger pod to become running: %v", err) } @@ -89,22 +122,22 @@ func TestBrokerTrigger(t *testing.T) { logger.Info("Creating Subscriber services") - for name, selector := range eventLoggers { - subscriberSvc := test.Service(name, ns, selector) - if err := WithServiceReady(clients, subscriberSvc, logger, cleaner); err != nil { - t.Fatalf("Error waiting for subscriber service to become ready: %v", err) - } + for _, dumper := range dumpers { + subscriberSvcName := name("svc", dumper.Broker, dumper.EventType, dumper.EventSource) + subscriberSvc := test.Service(subscriberSvcName, dumper.Namespace, dumper.Selector) } - logger.Info("Subscriber services ready") + logger.Info("Subscriber services created") logger.Info("Creating Triggers") - for name, selector := range eventLoggers { - strs := strings.Split(name, "-") - _, brokerName, eventType, eventSource := strs[0], strs[1], strs[2], strs[3] - trigger := test.Trigger(name, ns, eventType, eventSource, name) - err := WithTriggerReady(clients, defaultTrigger, logger, cleaner) + for _, dumper := range dumpers { + triggerName := name("trigger", dumper.Broker, dumper.EventType, dumper.EventSource) + // subscriberName should be the same as the subscriberSvc from before. + subscriberName := name("svc", dumper.Broker, dumper.EventType, dumper.EventSource) + trigger := test.Trigger(triggerName, dumper.Namespace, dumper.EventType, dumper.EventSource, dumper.Broker, subscriberName) + // Wait for the triggers to be ready + err := WithTriggerReady(clients, trigger, logger, cleaner) if err != nil { t.Fatalf("Error waiting for trigger to become ready: %v", err) } @@ -112,34 +145,63 @@ func TestBrokerTrigger(t *testing.T) { logger.Info("Triggers ready") - typesAndSources = []TypeAndSource{ - {eventType1, eventSource1}, - {eventType1, eventSource2}, - {eventType2, eventSource1}, - {eventType2, eventSource2}, - } + logger.Info("Creating event sender pods") - logger.Infof("Creating event sender pods") - // TODO should create a single pod that can send multiple events - for event := range typesAndSources { + for _, sender := range senders { + // Create cloud event. body := fmt.Sprintf("Testing Broker-Trigger %s", uuid.NewUUID()) cloudEvent := test.CloudEvent{ - Source: event.Source, - Type: event.Type, + Source: sender.EventSource, + Type: sender.EventType, Data: fmt.Sprintf(`{"msg":%q}`, body), - Encoding: encoding, + Encoding: test.CloudEventEncodingStructured, } - url := fmt.Sprintf("http://%s", defaultBroker.Status.Address.Hostname) - senderPod := test.EventSenderPod(event.Source, ns, url, cloudEvent) + // Create sender pod. + senderPodName := fmt.Sprintf("sender-%s-%s", sender.EventType, sender.EventSource) + senderPod := test.EventSenderPod(senderPodName, sender.Namespace, url, cloudEvent) logger.Infof("Sender pod: %#v", senderPod) if err := CreatePod(clients, senderPod, logger, cleaner); err != nil { t.Fatalf("Failed to create event sender pod: %v", err) } + + // Check on every dumper whether we should expect this event or not, and add its body if so. + for _, dumper := range dumpers { + if shouldExpectEvent(dumper, sender) { + dumper.ExpectedBodies = append(dumper.ExpectedBodies, body) + } + } } - // Verify that each event arrived to its own place. - if err := WaitForLogContent(clients, logger, routeName, subscriberPod.Spec.Containers[0].Name, ns, body); err != nil { - t.Fatalf("String %q not found in logs of subscriber pod %q: %v", body, routeName, err) + logger.Info("Created event sender pods") + + // Wait for all of them to be running. + if err := WaitForAllPodsRunning(clients, logger, ns); err != nil { + t.Fatalf("Error waiting for event sender pod to become running: %v", err) } + logger.Info("Verifying events arrived to appropriate dumpers") + + for _, dumper := range dumpers { + subscriberPodName := name("dumper", dumper.Broker, dumper.EventType, dumper.EventSource) + subscriberPod := subscriberPods[subscriberPodName] + if err := WaitForLogContents(clients, logger, routeName, subscriberPod.Spec.Containers[0].Name, dumper.Namespace, dumper.ExpectedBodies); err != nil { + t.Fatalf("String(s) not found in logs of subscriber pod %q: %v", subscriberPodName, err) + } + } + + logger.Info("Successfully completed!") + +} + +func shouldExpectEvent(dumper *DumperInfo, sender *SenderInfo) bool { + if dumper.Namespace != sender.Namespace { + return false + } + if dumper.EventType != any && dumper.EventType != sender.EventType { + return false + } + if dumper.EventSource != any && dumper != sender.EventSource { + return false + } + return true } diff --git a/test/e2e/builders.go b/test/e2e/builders.go deleted file mode 100644 index e89bb26f0a2..00000000000 --- a/test/e2e/builders.go +++ /dev/null @@ -1,116 +0,0 @@ -/* -Copyright 2019 The Knative Authors -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT 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 e2e - -import ( - eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// Broker builder. -type BrokerBuilder struct { - *eventingv1alpha1.Broker -} - -func NewBrokerBuilder(name, namespace string) *BrokerBuilder { - broker := &eventingv1alpha1.Broker{ - TypeMeta: metav1.TypeMeta{ - APIVersion: eventingv1alpha1.SchemeGroupVersion.String(), - Kind: "Broker", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: namespace, - }, - Spec: eventingv1alpha1.BrokerSpec{}, - } - - return &BrokerBuilder{ - Broker: broker, - } -} - -func (b *BrokerBuilder) Build() *eventingv1alpha1.Broker { - return b.Broker.DeepCopy() -} - -// Trigger builder. -type TriggerBuilder struct { - *eventingv1alpha1.Trigger -} - -func NewTriggerBuilder(name, namespace string) *TriggerBuilder { - trigger := &eventingv1alpha1.Trigger{ - TypeMeta: metav1.TypeMeta{ - APIVersion: eventingv1alpha1.SchemeGroupVersion.String(), - Kind: "Trigger", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: namespace, - }, - Spec: eventingv1alpha1.TriggerSpec{ - // Bind to 'default' Broker by default - Broker: "default", - Filter: &eventingv1alpha1.TriggerFilter{ - // Create a Any filter by default. - SourceAndType: &eventingv1alpha1.TriggerFilterSourceAndType{ - Source: eventingv1alpha1.TriggerAnyFilter, - Type: eventingv1alpha1.TriggerAnyFilter, - }, - }, - }, - } - - return &TriggerBuilder{ - Trigger: trigger, - } -} - -func (t *TriggerBuilder) Build() *eventingv1alpha1.Trigger { - return t.Trigger.DeepCopy() -} - -func (t *TriggerBuilder) Type(eventType string) *TriggerBuilder { - t.Trigger.Spec.Filter.SourceAndType.Type = eventType - return t -} - -func (t *TriggerBuilder) Source(eventSource string) *TriggerBuilder { - t.Trigger.Spec.Filter.SourceAndType.Source = eventSource - return t -} - -func (t *TriggerBuilder) Broker(brokerName string) *TriggerBuilder { - t.Trigger.Spec.Broker = brokerName - return t -} - -func (t *TriggerBuilder) Subscriber(ref *corev1.ObjectReference) *TriggerBuilder { - t.Trigger.Spec.Subscriber.Ref = ref - return t -} - -func (t *TriggerBuilder) SubscriberSvc(svcName string) *TriggerBuilder { - t.Trigger.Spec.Subscriber.Ref = &corev1.ObjectReference{ - APIVersion: corev1.SchemeGroupVersion.String(), - Kind: "Service", - Name: svcName, - Namespace: t.Trigger.GetNamespace(), - } - return t -} diff --git a/test/e2e/e2e.go b/test/e2e/e2e.go index 756c161ccdd..7a4976621b9 100644 --- a/test/e2e/e2e.go +++ b/test/e2e/e2e.go @@ -296,26 +296,6 @@ func CreateService(clients *test.Clients, svc *corev1.Service, logger *logging.B return nil } -// WithServiceReady creates a Service and waits until it is Ready. -func WithServiceReady(clients *test.Clients, svc *corev1.Service, logger *logging.BaseLogger, cleaner *test.Cleaner) error { - if err := CreateService(clients, svc, logger, cleaner); err != nil { - return err - } - - svcs := clients.Kube.Kube.CoreV1().Services(pkgTest.Flags.Namespace) - if err := test.WaitForServiceState(svcs, svc.Name, test.IsServiceReady, "ServiceIsReady"); err != nil { - return err - } - // Update the given object so they'll reflect the ready state - updatedSvc, err := svcs.Get(svc.Name, metav1.GetOptions{}) - if err != nil { - return err - } - updatedSvc.DeepCopyInto(svc) - - return nil -} - // CreatePod will create a Pod func CreatePod(clients *test.Clients, pod *corev1.Pod, logger *logging.BaseLogger, cleaner *test.Cleaner) error { pods := clients.Kube.Kube.CoreV1().Pods(pod.GetNamespace()) @@ -351,18 +331,30 @@ func PodLogs(clients *test.Clients, podName string, containerName string, namesp return nil, fmt.Errorf("Could not find logs for %s/%s", podName, containerName) } -// WaitForLogContent waits until logs for given Pod/Container include the given content. -// If the content is not present within timeout it returns error. -func WaitForLogContent(clients *test.Clients, logger *logging.BaseLogger, podName string, containerName string, namespace string, content string) error { +// WaitForLogContents waits until logs for given Pod/Container include the given contents. +// If the contents are not present within timeout it returns error. +func WaitForLogContents(clients *test.Clients, logger *logging.BaseLogger, podName string, containerName string, namespace string, contents []string) error { return wait.PollImmediate(interval, timeout, func() (bool, error) { logs, err := PodLogs(clients, podName, containerName, namespace, logger) if err != nil { return true, err } - return strings.Contains(string(logs), content), nil + for _, content := range contents { + if !strings.Contains(string(logs), content) { + logger.Infof("Could not find content %s for %s/%s", content, podName, containerName) + return false, nil + } + } + return true, nil }) } +// WaitForLogContent waits until logs for given Pod/Container include the given content. +// If the content is not present within timeout it returns error. +func WaitForLogContent(clients *test.Clients, logger *logging.BaseLogger, podName string, containerName string, namespace string, content string) error { + return WaitForLogContents(clients, logger, podName, containerName, namespace, []string{content}) +} + // WaitForAllPodsRunning will wait until all pods in the given namespace are running func WaitForAllPodsRunning(clients *test.Clients, logger *logging.BaseLogger, namespace string) error { if err := pkgTest.WaitForPodListState(clients.Kube, test.PodsRunning, "PodsAreRunning", namespace); err != nil { diff --git a/test/e2e/fixtures.go b/test/e2e/fixtures.go deleted file mode 100644 index 3bfa969bd7d..00000000000 --- a/test/e2e/fixtures.go +++ /dev/null @@ -1,109 +0,0 @@ -/* -Copyright 2019 The Knative Authors -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT 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 e2e - -import ( - "context" - - "github.com/knative/eventing/pkg/reconciler/testing" - "github.com/knative/pkg/apis/duck" - duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" - "k8s.io/apimachinery/pkg/api/meta" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - - "sigs.k8s.io/controller-runtime/pkg/client" -) - -type Fixture interface { - // Create attempts to instantiate the fixture. It may be called multiple times if earlier attempts return an error. - Create(context.Context, client.Client) error - - // Verify determines if the fixture was successfully instantiated once. It may be called multiple times if earlier - // attempts return false or an error. - Verify(context.Context, client.Client) (bool, error) - - // Debug surfaces context about a failure during Create or Verify. - Debug(context.Context, client.Client) - - // Teardown removes any state instantiated by Create or Verify. - Teardown(context.Context, client.Client) error -} - -type KnativeFixture struct { - Object testing.Buildable -} - -type CreateFunc func(context.Context, client.Client) error -type VerifyFunc func(context.Context, client.Client) (bool, error) -type DebugFunc func(context.Context, client.Client) -type TeardownFunc func(context.Context, client.Client) error - -type FixtureFuncs struct { - Create CreateFunc - Verify VerifyFunc - Debug DebugFunc - Teardown TeardownFunc -} - -//Fixtures: -// - Broker, Trigger Verify checks status ready -// - Sendevent Verify checks that pod completed successfully -// - Logevent Verify checks that the expected message was logged - -func (f *KnativeFixture) Create(ctx context.Context, cl client.Client) error { - obj := f.Object.Build() - err := cl.Create(ctx, obj) - if err != nil { - return err - } - return nil -} - -var standardCondSet = duckv1alpha1.NewLivingConditionSet() - -// TODO the runner should do this with backoff and retry. -// This method only verifies Knative objects -func (f *KnativeFixture) Verify(ctx context.Context, cl client.Client) (bool, error) { - obj := f.Object.Build() - u := &unstructured.Unstructured{} - acc, err := meta.Accessor(obj) - if err != nil { - return false, err - } - if err := cl.Get(ctx, client.ObjectKey{Name: acc.GetName(), Namespace: acc.GetNamespace()}, u); err != nil { - return false, err - } - - kr := &duckv1alpha1.KResource{} - if err := duck.FromUnstructured(u, kr); err != nil { - return false, err - } - - if !standardCondSet.Manage(kr.Status).IsHappy() { - return false, nil - } - - return true, nil -} - -// TODO If Create or Verify return an error, run this method, then Cleanup -func (f *KnativeFixture) Debug(ctx context.Context, cl client.Client) { -} - -// TODO if Teardown returns an error, log it and give up (maybe retry for a while?) -func (f *KnativeFixture) Teardown(ctx context.Context, cl client.Client) error { - obj := f.Object.Build() - return cl.Delete(ctx, obj) -} From 1edbf0a0a9485d7402c1e9d4b9fc83f3f04d53dd Mon Sep 17 00:00:00 2001 From: nachocano Date: Wed, 20 Feb 2019 11:18:30 -0800 Subject: [PATCH 071/221] Compiling --- test/e2e/broker_trigger_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/broker_trigger_test.go b/test/e2e/broker_trigger_test.go index bb7821d9187..9c7d523c390 100644 --- a/test/e2e/broker_trigger_test.go +++ b/test/e2e/broker_trigger_test.go @@ -200,7 +200,7 @@ func shouldExpectEvent(dumper *DumperInfo, sender *SenderInfo) bool { if dumper.EventType != any && dumper.EventType != sender.EventType { return false } - if dumper.EventSource != any && dumper != sender.EventSource { + if dumper.EventSource != any && dumper.EventType != sender.EventSource { return false } return true From 9c415e67674f210431013f762fef915aeb88cee5 Mon Sep 17 00:00:00 2001 From: nachocano Date: Wed, 20 Feb 2019 11:23:43 -0800 Subject: [PATCH 072/221] Fixing compilation --- test/e2e/broker_trigger_test.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/test/e2e/broker_trigger_test.go b/test/e2e/broker_trigger_test.go index 9c7d523c390..34e1c67ae9f 100644 --- a/test/e2e/broker_trigger_test.go +++ b/test/e2e/broker_trigger_test.go @@ -86,18 +86,18 @@ func TestBrokerTrigger(t *testing.T) { // Create sender helpers. senders := []SenderInfo{ - {ns, defaultBrokerUrl, eventType1, eventSource1}, - {ns, defaultBrokerUrl, eventType1, eventSource2}, - {ns, defaultBrokerUrl, eventType2, eventSource1}, - {ns, defaultBrokerUrl, eventType2, eventSource2}, + SenderInfo{ns, defaultBrokerUrl, eventType1, eventSource1}, + SenderInfo{ns, defaultBrokerUrl, eventType1, eventSource2}, + SenderInfo{ns, defaultBrokerUrl, eventType2, eventSource1}, + SenderInfo{ns, defaultBrokerUrl, eventType2, eventSource2}, } // Create DumperInfo helpers. dumpers := []DumperInfo{ - {ns, defaultBrokerName, any, any, {selectorKey: string(uuid.NewUUID())}, make([]string, 0)}, - {ns, defaultBrokerName, eventType1, any, {selectorKey: string(uuid.NewUUID())}, make([]string, 0)}, - {ns, defaultBrokerName, any, eventSource1, {selectorKey: string(uuid.NewUUID())}, make([]string, 0)}, - {ns, defaultBrokerName, eventType1, eventSource1, {selectorKey: string(uuid.NewUUID())}, make([]string, 0)}, + DumperInfo{ns, defaultBrokerName, any, any, {selectorKey: string(uuid.NewUUID())}, make([]string, 0)}, + DumperInfo{ns, defaultBrokerName, eventType1, any, {selectorKey: string(uuid.NewUUID())}, make([]string, 0)}, + DumperInfo{ns, defaultBrokerName, any, eventSource1, {selectorKey: string(uuid.NewUUID())}, make([]string, 0)}, + DumperInfo{ns, defaultBrokerName, eventType1, eventSource1, {selectorKey: string(uuid.NewUUID())}, make([]string, 0)}, } logger.Info("Creating Subscriber pods") @@ -158,7 +158,7 @@ func TestBrokerTrigger(t *testing.T) { } // Create sender pod. senderPodName := fmt.Sprintf("sender-%s-%s", sender.EventType, sender.EventSource) - senderPod := test.EventSenderPod(senderPodName, sender.Namespace, url, cloudEvent) + senderPod := test.EventSenderPod(senderPodName, sender.Namespace, sender.Url, cloudEvent) logger.Infof("Sender pod: %#v", senderPod) if err := CreatePod(clients, senderPod, logger, cleaner); err != nil { t.Fatalf("Failed to create event sender pod: %v", err) From ac9b485c525ba17ffbbae78bb0f4e29e24e40d2a Mon Sep 17 00:00:00 2001 From: nachocano Date: Wed, 20 Feb 2019 12:50:00 -0800 Subject: [PATCH 073/221] Fixing compilation errors. Adding AnnotateNamespace function. --- test/e2e/broker_trigger_test.go | 62 +++++++++++++-------------------- test/e2e/e2e.go | 17 ++++++--- test/e2e/single_event_test.go | 2 +- test/helpers.go | 36 +++++++++++++++++++ 4 files changed, 74 insertions(+), 43 deletions(-) create mode 100644 test/helpers.go diff --git a/test/e2e/broker_trigger_test.go b/test/e2e/broker_trigger_test.go index 34e1c67ae9f..9ee7c6b2084 100644 --- a/test/e2e/broker_trigger_test.go +++ b/test/e2e/broker_trigger_test.go @@ -45,39 +45,25 @@ func name(obj, brokerName, eventType, eventSource string) string { return fmt.Sprintf("%s-%s-%s-%s", obj, brokerName, eventType, eventSource) } -// Helper object to easily create subscriber pods, services and triggers. -// We also use this to verify the expected events that should be received -// by the particular subscriber pods. -type DumperInfo struct { - Namespace string - Broker string - EventType string - EventSource string - Selector map[string]string - ExpectedBodies []string -} - -// Helper object to easily create event sender pods. -type SenderInfo struct { - Namespace string - Url string - EventType string - EventSource string -} - func TestBrokerTrigger(t *testing.T) { logger := logging.GetContextLogger("TestBrokerTrigger") clients, cleaner := Setup(t, logger) defer TearDown(clients, cleaner, logger) - // Verify namespace and annotate to create default broker. - ns, cleanupNS := NamespaceExists(t, clients, logger, true) + // Verify namespace exists. + ns, cleanupNS := NamespaceExists(t, clients, logger) defer cleanupNS() + // Annotate namespace so that it creates the default broker. + err := AnnotateNamespace(clients, logger, map[string]string{"eventing.knative.dev/inject": "true"}) + if err != nil { + t.Fatalf("Error annotating namespace: %v", err) + } + // Wait for default broker ready. defaultBroker := test.Broker(defaultBrokerName, ns) - err := WaitForBrokerReady(clients, defaultBroker) + err = WaitForBrokerReady(clients, defaultBroker) if err != nil { t.Fatalf("Error waiting for default broker to become ready: %v", err) } @@ -85,19 +71,19 @@ func TestBrokerTrigger(t *testing.T) { defaultBrokerUrl := fmt.Sprintf("http://%s", defaultBroker.Status.Address.Hostname) // Create sender helpers. - senders := []SenderInfo{ - SenderInfo{ns, defaultBrokerUrl, eventType1, eventSource1}, - SenderInfo{ns, defaultBrokerUrl, eventType1, eventSource2}, - SenderInfo{ns, defaultBrokerUrl, eventType2, eventSource1}, - SenderInfo{ns, defaultBrokerUrl, eventType2, eventSource2}, + senders := []test.SenderInfo{ + {ns, defaultBrokerUrl, eventType1, eventSource1}, + {ns, defaultBrokerUrl, eventType1, eventSource2}, + {ns, defaultBrokerUrl, eventType2, eventSource1}, + {ns, defaultBrokerUrl, eventType2, eventSource2}, } - // Create DumperInfo helpers. - dumpers := []DumperInfo{ - DumperInfo{ns, defaultBrokerName, any, any, {selectorKey: string(uuid.NewUUID())}, make([]string, 0)}, - DumperInfo{ns, defaultBrokerName, eventType1, any, {selectorKey: string(uuid.NewUUID())}, make([]string, 0)}, - DumperInfo{ns, defaultBrokerName, any, eventSource1, {selectorKey: string(uuid.NewUUID())}, make([]string, 0)}, - DumperInfo{ns, defaultBrokerName, eventType1, eventSource1, {selectorKey: string(uuid.NewUUID())}, make([]string, 0)}, + // Create dumper helpers. + dumpers := []test.DumperInfo{ + {ns, defaultBrokerName, any, any, map[string]string{selectorKey: string(uuid.NewUUID())}, make([]string, 0)}, + {ns, defaultBrokerName, eventType1, any, map[string]string{selectorKey: string(uuid.NewUUID())}, make([]string, 0)}, + {ns, defaultBrokerName, any, eventSource1, map[string]string{selectorKey: string(uuid.NewUUID())}, make([]string, 0)}, + {ns, defaultBrokerName, eventType1, eventSource1, map[string]string{selectorKey: string(uuid.NewUUID())}, make([]string, 0)}, } logger.Info("Creating Subscriber pods") @@ -124,7 +110,7 @@ func TestBrokerTrigger(t *testing.T) { for _, dumper := range dumpers { subscriberSvcName := name("svc", dumper.Broker, dumper.EventType, dumper.EventSource) - subscriberSvc := test.Service(subscriberSvcName, dumper.Namespace, dumper.Selector) + test.Service(subscriberSvcName, dumper.Namespace, dumper.Selector) } logger.Info("Subscriber services created") @@ -166,7 +152,7 @@ func TestBrokerTrigger(t *testing.T) { // Check on every dumper whether we should expect this event or not, and add its body if so. for _, dumper := range dumpers { - if shouldExpectEvent(dumper, sender) { + if shouldExpectEvent(&dumper, &sender) { dumper.ExpectedBodies = append(dumper.ExpectedBodies, body) } } @@ -184,7 +170,7 @@ func TestBrokerTrigger(t *testing.T) { for _, dumper := range dumpers { subscriberPodName := name("dumper", dumper.Broker, dumper.EventType, dumper.EventSource) subscriberPod := subscriberPods[subscriberPodName] - if err := WaitForLogContents(clients, logger, routeName, subscriberPod.Spec.Containers[0].Name, dumper.Namespace, dumper.ExpectedBodies); err != nil { + if err := WaitForLogContents(clients, logger, subscriberPodName, subscriberPod.Spec.Containers[0].Name, dumper.Namespace, dumper.ExpectedBodies); err != nil { t.Fatalf("String(s) not found in logs of subscriber pod %q: %v", subscriberPodName, err) } } @@ -193,7 +179,7 @@ func TestBrokerTrigger(t *testing.T) { } -func shouldExpectEvent(dumper *DumperInfo, sender *SenderInfo) bool { +func shouldExpectEvent(dumper *test.DumperInfo, sender *test.SenderInfo) bool { if dumper.Namespace != sender.Namespace { return false } diff --git a/test/e2e/e2e.go b/test/e2e/e2e.go index 7a4976621b9..3c45ded21ef 100644 --- a/test/e2e/e2e.go +++ b/test/e2e/e2e.go @@ -363,7 +363,19 @@ func WaitForAllPodsRunning(clients *test.Clients, logger *logging.BaseLogger, na return nil } -func NamespaceExists(t *testing.T, clients *test.Clients, logger *logging.BaseLogger, annotate bool) (string, func()) { +// AnnotateNamespace annotates the test namespace with the annotations map +func AnnotateNamespace(clients *test.Clients, logger *logging.BaseLogger, annotations map[string]string) error { + ns := pkgTest.Flags.Namespace + nsSpec, err := clients.Kube.Kube.CoreV1().Namespaces().Get(ns, metav1.GetOptions{}) + if err != nil && errors.IsNotFound(err) { + return err + } + nsSpec.Annotations = annotations + _, err = clients.Kube.Kube.CoreV1().Namespaces().Update(nsSpec) + return err +} + +func NamespaceExists(t *testing.T, clients *test.Clients, logger *logging.BaseLogger) (string, func()) { shutdown := func() {} ns := pkgTest.Flags.Namespace logger.Infof("Namespace: %s", ns) @@ -372,9 +384,6 @@ func NamespaceExists(t *testing.T, clients *test.Clients, logger *logging.BaseLo if err != nil && errors.IsNotFound(err) { nsSpec = &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: ns}} - if annotate { - nsSpec.Annotations = map[string]string{"eventing.knative.dev/inject": "true"} - } logger.Infof("Creating Namespace: %s", ns) nsSpec, err = clients.Kube.Kube.CoreV1().Namespaces().Create(nsSpec) diff --git a/test/e2e/single_event_test.go b/test/e2e/single_event_test.go index 8ccf04037fe..a1d9455c71d 100644 --- a/test/e2e/single_event_test.go +++ b/test/e2e/single_event_test.go @@ -51,7 +51,7 @@ func SingleEvent(t *testing.T, encoding string) { // verify namespace - ns, cleanupNS := NamespaceExists(t, clients, logger, false) + ns, cleanupNS := NamespaceExists(t, clients, logger) defer cleanupNS() // create logger pod diff --git a/test/helpers.go b/test/helpers.go new file mode 100644 index 00000000000..3dec1061c90 --- /dev/null +++ b/test/helpers.go @@ -0,0 +1,36 @@ +/* +Copyright 2019 The Knative Authors +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT 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 test + +// Helper struct to easily create subscriber pods, services and triggers. +// We also use this to verify the expected events that should be received +// by the particular subscriber pods. +type DumperInfo struct { + Namespace string + Broker string + EventType string + EventSource string + Selector map[string]string + ExpectedBodies []string +} + +// Helper struct to easily create event sender pods. +type SenderInfo struct { + Namespace string + Url string + EventType string + EventSource string +} From 2b3916808ff2e9bb23e8702ec8fa7e9c139f0468 Mon Sep 17 00:00:00 2001 From: nachocano Date: Wed, 20 Feb 2019 13:11:26 -0800 Subject: [PATCH 074/221] Adding ns --- test/e2e/e2e.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/e2e/e2e.go b/test/e2e/e2e.go index 3c45ded21ef..929a6e93944 100644 --- a/test/e2e/e2e.go +++ b/test/e2e/e2e.go @@ -163,12 +163,12 @@ func WithChannelAndSubscriptionReady(clients *test.Clients, channel *v1alpha1.Ch // CreateBroker will create a Broker func CreateBroker(clients *test.Clients, broker *v1alpha1.Broker, logger *logging.BaseLogger, cleaner *test.Cleaner) error { - brokers := clients.Eventing.EventingV1alpha1().Brokers(pkgTest.Flags.Namespace) + brokers := clients.Eventing.EventingV1alpha1().Brokers(broker.Namespace) res, err := brokers.Create(broker) if err != nil { return err } - cleaner.Add(v1alpha1.SchemeGroupVersion.Group, v1alpha1.SchemeGroupVersion.Version, "brokers", pkgTest.Flags.Namespace, res.ObjectMeta.Name) + cleaner.Add(v1alpha1.SchemeGroupVersion.Group, v1alpha1.SchemeGroupVersion.Version, "brokers", broker.Namespace, res.ObjectMeta.Name) return nil } @@ -182,7 +182,7 @@ func WithBrokerReady(clients *test.Clients, broker *v1alpha1.Broker, logger *log // WaitForBrokerReady waits until the broker is Ready. func WaitForBrokerReady(clients *test.Clients, broker *v1alpha1.Broker) error { - brokers := clients.Eventing.EventingV1alpha1().Brokers(pkgTest.Flags.Namespace) + brokers := clients.Eventing.EventingV1alpha1().Brokers(broker.Namespace) if err := test.WaitForBrokerState(brokers, broker.Name, test.IsBrokerReady, "BrokerIsReady"); err != nil { return err } @@ -197,12 +197,12 @@ func WaitForBrokerReady(clients *test.Clients, broker *v1alpha1.Broker) error { // CreateTrigger will create a Trigger func CreateTrigger(clients *test.Clients, trigger *v1alpha1.Trigger, logger *logging.BaseLogger, cleaner *test.Cleaner) error { - triggers := clients.Eventing.EventingV1alpha1().Triggers(pkgTest.Flags.Namespace) + triggers := clients.Eventing.EventingV1alpha1().Triggers(trigger.Namespace) res, err := triggers.Create(trigger) if err != nil { return err } - cleaner.Add(v1alpha1.SchemeGroupVersion.Group, v1alpha1.SchemeGroupVersion.Version, "triggers", pkgTest.Flags.Namespace, res.ObjectMeta.Name) + cleaner.Add(v1alpha1.SchemeGroupVersion.Group, v1alpha1.SchemeGroupVersion.Version, "triggers", trigger.Namespace, res.ObjectMeta.Name) return nil } @@ -212,7 +212,7 @@ func WithTriggerReady(clients *test.Clients, trigger *v1alpha1.Trigger, logger * return err } - triggers := clients.Eventing.EventingV1alpha1().Triggers(pkgTest.Flags.Namespace) + triggers := clients.Eventing.EventingV1alpha1().Triggers(trigger.Namespace) if err := test.WaitForTriggerState(triggers, trigger.Name, test.IsTriggerReady, "TriggerIsReady"); err != nil { return err } From ed9fcbe46dd1286240e406104c00ca06e8301f52 Mon Sep 17 00:00:00 2001 From: nachocano Date: Wed, 20 Feb 2019 13:19:45 -0800 Subject: [PATCH 075/221] Adding logs. Changing to lowercase any otherwise the pod name is invalid --- test/e2e/broker_trigger_test.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/test/e2e/broker_trigger_test.go b/test/e2e/broker_trigger_test.go index 9ee7c6b2084..71972138e35 100644 --- a/test/e2e/broker_trigger_test.go +++ b/test/e2e/broker_trigger_test.go @@ -21,8 +21,6 @@ import ( "fmt" "testing" - "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" - "github.com/knative/eventing/test" "github.com/knative/pkg/test/logging" corev1 "k8s.io/api/core/v1" @@ -33,7 +31,7 @@ const ( defaultBrokerName = "default" selectorKey = "end2end-test-broker-trigger" - any = v1alpha1.TriggerAnyFilter + any = "any" eventType1 = "type1" eventType2 = "type2" eventSource1 = "source1" @@ -55,12 +53,16 @@ func TestBrokerTrigger(t *testing.T) { ns, cleanupNS := NamespaceExists(t, clients, logger) defer cleanupNS() + logger.Infof("Annotating namespace %s", ns) + // Annotate namespace so that it creates the default broker. err := AnnotateNamespace(clients, logger, map[string]string{"eventing.knative.dev/inject": "true"}) if err != nil { t.Fatalf("Error annotating namespace: %v", err) } + logger.Infof("Namespace %s annotated", ns) + // Wait for default broker ready. defaultBroker := test.Broker(defaultBrokerName, ns) err = WaitForBrokerReady(clients, defaultBroker) From 484895291eb8258f66760d6f89d82014012be15a Mon Sep 17 00:00:00 2001 From: nachocano Date: Wed, 20 Feb 2019 13:38:58 -0800 Subject: [PATCH 076/221] Removing namespace when creating trigger subscriber spec. Adding wait time constant for default broker creation. --- test/crd.go | 1 - test/e2e/broker_trigger_test.go | 13 +++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/test/crd.go b/test/crd.go index f9f350e5939..198ce679d0b 100644 --- a/test/crd.go +++ b/test/crd.go @@ -199,7 +199,6 @@ func Trigger(name, namespace, eventType, eventSource, brokerName, svcName string APIVersion: corev1.SchemeGroupVersion.String(), Kind: "Service", Name: svcName, - Namespace: namespace, }, }, }, diff --git a/test/e2e/broker_trigger_test.go b/test/e2e/broker_trigger_test.go index 71972138e35..e65d94ad87f 100644 --- a/test/e2e/broker_trigger_test.go +++ b/test/e2e/broker_trigger_test.go @@ -20,6 +20,7 @@ package e2e import ( "fmt" "testing" + "time" "github.com/knative/eventing/test" "github.com/knative/pkg/test/logging" @@ -28,8 +29,9 @@ import ( ) const ( - defaultBrokerName = "default" - selectorKey = "end2end-test-broker-trigger" + defaultBrokerName = "default" + waitForDefaultBrokerCreation = 3 * time.Second + selectorKey = "end2end-test-broker-trigger" any = "any" eventType1 = "type1" @@ -63,6 +65,13 @@ func TestBrokerTrigger(t *testing.T) { logger.Infof("Namespace %s annotated", ns) + // As we are not creating the default broker, + // we wait for a few seconds for the broker to get created. + // Otherwise, if we try to wait for its Ready status and the namespace controller + // didn't create it yet, it fails. + logger.Info("Waiting for default broker creation") + time.Sleep(waitForDefaultBrokerCreation) + // Wait for default broker ready. defaultBroker := test.Broker(defaultBrokerName, ns) err = WaitForBrokerReady(clients, defaultBroker) From 311e174a64e4359b1ee7f6c74f33c2b2053bc363 Mon Sep 17 00:00:00 2001 From: nachocano Date: Wed, 20 Feb 2019 14:24:56 -0800 Subject: [PATCH 077/221] Checking if all triggers are ready --- test/crd.go | 6 +++--- test/crd_checks.go | 18 ++++++++++++++++++ test/e2e/broker_trigger_test.go | 28 +++++++++++++++++++--------- test/e2e/e2e.go | 9 +++++++++ test/states.go | 16 ++++++++++++++++ 5 files changed, 65 insertions(+), 12 deletions(-) diff --git a/test/crd.go b/test/crd.go index 198ce679d0b..5121cd925a1 100644 --- a/test/crd.go +++ b/test/crd.go @@ -180,14 +180,14 @@ func Broker(name string, namespace string) *v1alpha1.Broker { } // Trigger returns a Trigger. -func Trigger(name, namespace, eventType, eventSource, brokerName, svcName string) *v1alpha1.Trigger { +func Trigger(name, namespace, eventType, eventSource, broker, svcName string) *v1alpha1.Trigger { return &v1alpha1.Trigger{ ObjectMeta: metav1.ObjectMeta{ Name: name, Namespace: namespace, }, Spec: v1alpha1.TriggerSpec{ - Broker: brokerName, + Broker: broker, Filter: &v1alpha1.TriggerFilter{ SourceAndType: &v1alpha1.TriggerFilterSourceAndType{ Type: fmt.Sprintf("%q", eventType), @@ -196,7 +196,7 @@ func Trigger(name, namespace, eventType, eventSource, brokerName, svcName string }, Subscriber: &v1alpha1.SubscriberSpec{ Ref: &corev1.ObjectReference{ - APIVersion: corev1.SchemeGroupVersion.String(), + APIVersion: "v1", Kind: "Service", Name: svcName, }, diff --git a/test/crd_checks.go b/test/crd_checks.go index 6c66fc03ab9..93648af5707 100644 --- a/test/crd_checks.go +++ b/test/crd_checks.go @@ -132,6 +132,24 @@ func WaitForTriggerState(client eventingclient.TriggerInterface, name string, in }) } +// WaitForTriggersListState polls the status of the TriggerList +// from client every interval until inState returns `true` indicating it +// is done, returns an error or timeout. desc will be used to name the metric +// that is emitted to track how long it took to get into the state checked by inState. +func WaitForTriggersListState(clients eventingclient.TriggerInterface, inState func(t *eventingv1alpha1.TriggerList) (bool, error), desc string) error { + metricName := fmt.Sprintf("WaitForTriggerListState/%s", desc) + _, span := trace.StartSpan(context.Background(), metricName) + defer span.End() + + return wait.PollImmediate(interval, timeout, func() (bool, error) { + t, err := clients.List(metav1.ListOptions{}) + if err != nil { + return true, err + } + return inState(t) + }) +} + // WaitForServiceState polls the status of the Service called name from client // every interval until inState returns `true` indicating it is done, returns an // error or timeout. desc will be used to name the metric that is emitted to diff --git a/test/e2e/broker_trigger_test.go b/test/e2e/broker_trigger_test.go index e65d94ad87f..55611971497 100644 --- a/test/e2e/broker_trigger_test.go +++ b/test/e2e/broker_trigger_test.go @@ -19,9 +19,12 @@ package e2e import ( "fmt" + "strings" "testing" "time" + "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" + "github.com/knative/eventing/test" "github.com/knative/pkg/test/logging" corev1 "k8s.io/api/core/v1" @@ -33,7 +36,7 @@ const ( waitForDefaultBrokerCreation = 3 * time.Second selectorKey = "end2end-test-broker-trigger" - any = "any" + any = v1alpha1.TriggerAnyFilter eventType1 = "type1" eventType2 = "type2" eventSource1 = "source1" @@ -42,7 +45,8 @@ const ( // Helper function to create names for different objects (e.g., triggers, services, etc.) func name(obj, brokerName, eventType, eventSource string) string { - return fmt.Sprintf("%s-%s-%s-%s", obj, brokerName, eventType, eventSource) + // pod names need to be lowercase. We might have an eventType as Any, that is why we lowercase them. + return strings.ToLower(fmt.Sprintf("%s-%s-%s-%s", obj, brokerName, eventType, eventSource)) } func TestBrokerTrigger(t *testing.T) { @@ -105,7 +109,7 @@ func TestBrokerTrigger(t *testing.T) { subscriberPodName := name("dumper", dumper.Broker, dumper.EventType, dumper.EventSource) subscriberPod := test.EventLoggerPod(subscriberPodName, dumper.Namespace, dumper.Selector) if err := CreatePod(clients, subscriberPod, logger, cleaner); err != nil { - t.Fatalf("Failed to create subscriber pod: %v", err) + t.Fatalf("Error creating subscriber pod: %v", err) } subscriberPods[subscriberPodName] = subscriberPod } @@ -133,13 +137,19 @@ func TestBrokerTrigger(t *testing.T) { // subscriberName should be the same as the subscriberSvc from before. subscriberName := name("svc", dumper.Broker, dumper.EventType, dumper.EventSource) trigger := test.Trigger(triggerName, dumper.Namespace, dumper.EventType, dumper.EventSource, dumper.Broker, subscriberName) - // Wait for the triggers to be ready - err := WithTriggerReady(clients, trigger, logger, cleaner) + err := CreateTrigger(clients, trigger, logger, cleaner) if err != nil { - t.Fatalf("Error waiting for trigger to become ready: %v", err) + t.Fatalf("Error creating trigger: %v", err) } } + logger.Info("Triggers created") + + // Wait for all of them to be ready. + if err := WaitForAllTriggersReady(clients, logger, ns); err != nil { + t.Fatalf("Error waiting for triggers to become ready: %v", err) + } + logger.Info("Triggers ready") logger.Info("Creating event sender pods") @@ -154,11 +164,11 @@ func TestBrokerTrigger(t *testing.T) { Encoding: test.CloudEventEncodingStructured, } // Create sender pod. - senderPodName := fmt.Sprintf("sender-%s-%s", sender.EventType, sender.EventSource) + senderPodName := name("sender", "", sender.EventType, sender.EventSource) senderPod := test.EventSenderPod(senderPodName, sender.Namespace, sender.Url, cloudEvent) logger.Infof("Sender pod: %#v", senderPod) if err := CreatePod(clients, senderPod, logger, cleaner); err != nil { - t.Fatalf("Failed to create event sender pod: %v", err) + t.Fatalf("Error creating event sender pod: %v", err) } // Check on every dumper whether we should expect this event or not, and add its body if so. @@ -186,7 +196,7 @@ func TestBrokerTrigger(t *testing.T) { } } - logger.Info("Successfully completed!") + logger.Info("Verification successful!") } diff --git a/test/e2e/e2e.go b/test/e2e/e2e.go index 929a6e93944..5ff93f132b5 100644 --- a/test/e2e/e2e.go +++ b/test/e2e/e2e.go @@ -363,6 +363,15 @@ func WaitForAllPodsRunning(clients *test.Clients, logger *logging.BaseLogger, na return nil } +// WaitForAllTriggersReady will wait until all triggers in the given namespace are ready +func WaitForAllTriggersReady(clients *test.Clients, logger *logging.BaseLogger, namespace string) error { + triggers := clients.Eventing.EventingV1alpha1().Triggers(namespace) + if err := test.WaitForTriggersListState(triggers, test.TriggersReady, "TriggerIsReady"); err != nil { + return err + } + return nil +} + // AnnotateNamespace annotates the test namespace with the annotations map func AnnotateNamespace(clients *test.Clients, logger *logging.BaseLogger, annotations map[string]string) error { ns := pkgTest.Flags.Namespace diff --git a/test/states.go b/test/states.go index 26db82aee3d..a05e08728d0 100644 --- a/test/states.go +++ b/test/states.go @@ -66,6 +66,22 @@ func IsTriggerReady(t *eventingv1alpha1.Trigger) (bool, error) { return t.Status.IsReady(), nil } +// TriggersReady will check the status conditions of the trigger list and return true +// if all triggers are Ready. +func TriggersReady(triggerList *eventingv1alpha1.TriggerList) (bool, error) { + var names []string + for _, t := range triggerList.Items { + names = append(names, t.Name) + } + log.Printf("Checking triggers: %v", names) + for _, trigger := range triggerList.Items { + if !trigger.Status.IsReady() { + return false, nil + } + } + return true, nil +} + // PodsRunning will check the status conditions of the pod list and return true // if all pods are Running. func PodsRunning(podList *corev1.PodList) (bool, error) { From d361afb271079f0dd201f2ba32eb6ab4edb51fcc Mon Sep 17 00:00:00 2001 From: nachocano Date: Wed, 20 Feb 2019 14:47:45 -0800 Subject: [PATCH 078/221] Updated logs --- test/e2e/broker_trigger_test.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/test/e2e/broker_trigger_test.go b/test/e2e/broker_trigger_test.go index 55611971497..7a0056e3df1 100644 --- a/test/e2e/broker_trigger_test.go +++ b/test/e2e/broker_trigger_test.go @@ -72,7 +72,7 @@ func TestBrokerTrigger(t *testing.T) { // As we are not creating the default broker, // we wait for a few seconds for the broker to get created. // Otherwise, if we try to wait for its Ready status and the namespace controller - // didn't create it yet, it fails. + // didn't actually create it yet, the test will fail. logger.Info("Waiting for default broker creation") time.Sleep(waitForDefaultBrokerCreation) @@ -114,6 +114,8 @@ func TestBrokerTrigger(t *testing.T) { subscriberPods[subscriberPodName] = subscriberPod } + logger.Info("Subscriber pods created") + // Wait for all of them to be running. if err := WaitForAllPodsRunning(clients, logger, ns); err != nil { t.Fatalf("Error waiting for event logger pod to become running: %v", err) @@ -179,14 +181,14 @@ func TestBrokerTrigger(t *testing.T) { } } - logger.Info("Created event sender pods") + logger.Info("Event sender pods created") // Wait for all of them to be running. if err := WaitForAllPodsRunning(clients, logger, ns); err != nil { t.Fatalf("Error waiting for event sender pod to become running: %v", err) } - logger.Info("Verifying events arrived to appropriate dumpers") + logger.Info("Verifying events delivered to appropriate dumpers") for _, dumper := range dumpers { subscriberPodName := name("dumper", dumper.Broker, dumper.EventType, dumper.EventSource) From d1198a96e1e05d6d59705ca9fd2f801a21b21ebf Mon Sep 17 00:00:00 2001 From: nachocano Date: Wed, 20 Feb 2019 15:53:07 -0800 Subject: [PATCH 079/221] Working --- test/e2e/broker_trigger_test.go | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/test/e2e/broker_trigger_test.go b/test/e2e/broker_trigger_test.go index 7a0056e3df1..80ff3043315 100644 --- a/test/e2e/broker_trigger_test.go +++ b/test/e2e/broker_trigger_test.go @@ -77,12 +77,15 @@ func TestBrokerTrigger(t *testing.T) { time.Sleep(waitForDefaultBrokerCreation) // Wait for default broker ready. + logger.Info("Waiting for default broker to be ready") defaultBroker := test.Broker(defaultBrokerName, ns) err = WaitForBrokerReady(clients, defaultBroker) if err != nil { t.Fatalf("Error waiting for default broker to become ready: %v", err) } + logger.Info("Default broker ready") + defaultBrokerUrl := fmt.Sprintf("http://%s", defaultBroker.Status.Address.Hostname) // Create sender helpers. @@ -116,6 +119,8 @@ func TestBrokerTrigger(t *testing.T) { logger.Info("Subscriber pods created") + logger.Info("Waiting for subscriber pods to become running") + // Wait for all of them to be running. if err := WaitForAllPodsRunning(clients, logger, ns); err != nil { t.Fatalf("Error waiting for event logger pod to become running: %v", err) @@ -127,7 +132,10 @@ func TestBrokerTrigger(t *testing.T) { for _, dumper := range dumpers { subscriberSvcName := name("svc", dumper.Broker, dumper.EventType, dumper.EventSource) - test.Service(subscriberSvcName, dumper.Namespace, dumper.Selector) + service := test.Service(subscriberSvcName, dumper.Namespace, dumper.Selector) + if err := CreateService(clients, service, logger, cleaner); err != nil { + t.Fatalf("Error creating subscriber service: %v", err) + } } logger.Info("Subscriber services created") @@ -147,6 +155,8 @@ func TestBrokerTrigger(t *testing.T) { logger.Info("Triggers created") + logger.Info("Waiting for triggers to become ready") + // Wait for all of them to be ready. if err := WaitForAllTriggersReady(clients, logger, ns); err != nil { t.Fatalf("Error waiting for triggers to become ready: %v", err) @@ -168,7 +178,6 @@ func TestBrokerTrigger(t *testing.T) { // Create sender pod. senderPodName := name("sender", "", sender.EventType, sender.EventSource) senderPod := test.EventSenderPod(senderPodName, sender.Namespace, sender.Url, cloudEvent) - logger.Infof("Sender pod: %#v", senderPod) if err := CreatePod(clients, senderPod, logger, cleaner); err != nil { t.Fatalf("Error creating event sender pod: %v", err) } @@ -183,11 +192,15 @@ func TestBrokerTrigger(t *testing.T) { logger.Info("Event sender pods created") + logger.Info("Waiting for event sender pods to be running") + // Wait for all of them to be running. if err := WaitForAllPodsRunning(clients, logger, ns); err != nil { t.Fatalf("Error waiting for event sender pod to become running: %v", err) } + logger.Info("Event sender pods running") + logger.Info("Verifying events delivered to appropriate dumpers") for _, dumper := range dumpers { From 6bd659c4e940cd0031d66ecd7a0efda8a033b3a2 Mon Sep 17 00:00:00 2001 From: nachocano Date: Wed, 20 Feb 2019 16:45:10 -0800 Subject: [PATCH 080/221] Adding logs... Still not receiving the events. --- test/e2e/broker_trigger_test.go | 23 +++++++++++++---------- test/e2e/e2e.go | 4 ++-- test/helpers.go | 12 ++++++------ 3 files changed, 21 insertions(+), 18 deletions(-) diff --git a/test/e2e/broker_trigger_test.go b/test/e2e/broker_trigger_test.go index 80ff3043315..cad5b1d6887 100644 --- a/test/e2e/broker_trigger_test.go +++ b/test/e2e/broker_trigger_test.go @@ -1,5 +1,3 @@ -// +build e2e - /* Copyright 2019 The Knative Authors Licensed under the Apache License, Version 2.0 (the "License"); @@ -89,7 +87,7 @@ func TestBrokerTrigger(t *testing.T) { defaultBrokerUrl := fmt.Sprintf("http://%s", defaultBroker.Status.Address.Hostname) // Create sender helpers. - senders := []test.SenderInfo{ + senders := []*test.SenderInfo{ {ns, defaultBrokerUrl, eventType1, eventSource1}, {ns, defaultBrokerUrl, eventType1, eventSource2}, {ns, defaultBrokerUrl, eventType2, eventSource1}, @@ -97,7 +95,7 @@ func TestBrokerTrigger(t *testing.T) { } // Create dumper helpers. - dumpers := []test.DumperInfo{ + dumpers := []*test.DumperInfo{ {ns, defaultBrokerName, any, any, map[string]string{selectorKey: string(uuid.NewUUID())}, make([]string, 0)}, {ns, defaultBrokerName, eventType1, any, map[string]string{selectorKey: string(uuid.NewUUID())}, make([]string, 0)}, {ns, defaultBrokerName, any, eventSource1, map[string]string{selectorKey: string(uuid.NewUUID())}, make([]string, 0)}, @@ -168,7 +166,8 @@ func TestBrokerTrigger(t *testing.T) { for _, sender := range senders { // Create cloud event. - body := fmt.Sprintf("Testing Broker-Trigger %s", uuid.NewUUID()) + // Using event type and source as part of the body for easier debugging. + body := fmt.Sprintf("Body-%s-%s", sender.EventSource, sender.EventType) cloudEvent := test.CloudEvent{ Source: sender.EventSource, Type: sender.EventType, @@ -184,8 +183,8 @@ func TestBrokerTrigger(t *testing.T) { // Check on every dumper whether we should expect this event or not, and add its body if so. for _, dumper := range dumpers { - if shouldExpectEvent(&dumper, &sender) { - dumper.ExpectedBodies = append(dumper.ExpectedBodies, body) + if shouldExpectEvent(dumper, sender, logger) { + dumper.Expect = append(dumper.Expect, body) } } } @@ -206,7 +205,8 @@ func TestBrokerTrigger(t *testing.T) { for _, dumper := range dumpers { subscriberPodName := name("dumper", dumper.Broker, dumper.EventType, dumper.EventSource) subscriberPod := subscriberPods[subscriberPodName] - if err := WaitForLogContents(clients, logger, subscriberPodName, subscriberPod.Spec.Containers[0].Name, dumper.Namespace, dumper.ExpectedBodies); err != nil { + logger.Infof("Dumper %q expecting %q", subscriberPodName, strings.Join(dumper.Expect, ",")) + if err := WaitForLogContents(clients, logger, subscriberPodName, subscriberPod.Spec.Containers[0].Name, dumper.Namespace, dumper.Expect); err != nil { t.Fatalf("String(s) not found in logs of subscriber pod %q: %v", subscriberPodName, err) } } @@ -215,14 +215,17 @@ func TestBrokerTrigger(t *testing.T) { } -func shouldExpectEvent(dumper *test.DumperInfo, sender *test.SenderInfo) bool { +func shouldExpectEvent(dumper *test.DumperInfo, sender *test.SenderInfo, logger *logging.BaseLogger) bool { if dumper.Namespace != sender.Namespace { + logger.Debugf("Namespaces mismatch, dumper %s, sender %s", dumper.Namespace, sender.Namespace) return false } if dumper.EventType != any && dumper.EventType != sender.EventType { + logger.Debugf("Event types mismatch, dumper %s, sender %s", dumper.EventType, sender.EventType) return false } - if dumper.EventSource != any && dumper.EventType != sender.EventSource { + if dumper.EventSource != any && dumper.EventSource != sender.EventSource { + logger.Debugf("Event sources mismatch, dumper %s, sender %s", dumper.EventSource, sender.EventSource) return false } return true diff --git a/test/e2e/e2e.go b/test/e2e/e2e.go index 5ff93f132b5..4972f02eb75 100644 --- a/test/e2e/e2e.go +++ b/test/e2e/e2e.go @@ -321,7 +321,7 @@ func PodLogs(clients *test.Clients, podName string, containerName string, namesp }).Do() raw, err := result.Raw() if err == nil { - logger.Infof("%s logs request result: %#v", podName, string(raw)) + logger.Debugf("%s logs request result: %#v", podName, string(raw)) } else { logger.Infof("%s logs request result: %#v", podName, err) } @@ -341,7 +341,7 @@ func WaitForLogContents(clients *test.Clients, logger *logging.BaseLogger, podNa } for _, content := range contents { if !strings.Contains(string(logs), content) { - logger.Infof("Could not find content %s for %s/%s", content, podName, containerName) + logger.Infof("Could not find content %q for %s/%s. Found %q instead", content, podName, containerName, string(logs)) return false, nil } } diff --git a/test/helpers.go b/test/helpers.go index 3dec1061c90..d6e283cb87e 100644 --- a/test/helpers.go +++ b/test/helpers.go @@ -19,12 +19,12 @@ package test // We also use this to verify the expected events that should be received // by the particular subscriber pods. type DumperInfo struct { - Namespace string - Broker string - EventType string - EventSource string - Selector map[string]string - ExpectedBodies []string + Namespace string + Broker string + EventType string + EventSource string + Selector map[string]string + Expect []string } // Helper struct to easily create event sender pods. From 0d80f9ca1f8b060eae5966a6c68fcc4ba1fac1f4 Mon Sep 17 00:00:00 2001 From: nachocano Date: Wed, 20 Feb 2019 17:04:31 -0800 Subject: [PATCH 081/221] More logs --- test/e2e/broker_trigger_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/e2e/broker_trigger_test.go b/test/e2e/broker_trigger_test.go index cad5b1d6887..c70f040a51f 100644 --- a/test/e2e/broker_trigger_test.go +++ b/test/e2e/broker_trigger_test.go @@ -82,10 +82,10 @@ func TestBrokerTrigger(t *testing.T) { t.Fatalf("Error waiting for default broker to become ready: %v", err) } - logger.Info("Default broker ready") - defaultBrokerUrl := fmt.Sprintf("http://%s", defaultBroker.Status.Address.Hostname) + logger.Infof("Default broker ready: %q", defaultBrokerUrl) + // Create sender helpers. senders := []*test.SenderInfo{ {ns, defaultBrokerUrl, eventType1, eventSource1}, From cd862ffdbbc127c124488c3ab751ba85cb1e25e5 Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Wed, 20 Feb 2019 23:07:32 -0800 Subject: [PATCH 082/221] Adding build constraint --- test/e2e/broker_trigger_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/e2e/broker_trigger_test.go b/test/e2e/broker_trigger_test.go index c70f040a51f..b876156be2d 100644 --- a/test/e2e/broker_trigger_test.go +++ b/test/e2e/broker_trigger_test.go @@ -1,3 +1,5 @@ +// +build e2e + /* Copyright 2019 The Knative Authors Licensed under the Apache License, Version 2.0 (the "License"); @@ -71,6 +73,7 @@ func TestBrokerTrigger(t *testing.T) { // we wait for a few seconds for the broker to get created. // Otherwise, if we try to wait for its Ready status and the namespace controller // didn't actually create it yet, the test will fail. + // TODO improve logger.Info("Waiting for default broker creation") time.Sleep(waitForDefaultBrokerCreation) From 2ea7aa3ff4e31a2ff4a6697bf6f5c9efcc210543 Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Wed, 20 Feb 2019 23:14:02 -0800 Subject: [PATCH 083/221] Removing unnecessary stuff --- test/crd_checks.go | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/test/crd_checks.go b/test/crd_checks.go index 93648af5707..faebe200ed4 100644 --- a/test/crd_checks.go +++ b/test/crd_checks.go @@ -23,10 +23,6 @@ import ( "fmt" "time" - v1 "k8s.io/client-go/kubernetes/typed/core/v1" - - corev1 "k8s.io/api/core/v1" - eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" eventingclient "github.com/knative/eventing/pkg/client/clientset/versioned/typed/eventing/v1alpha1" servingv1alpha1 "github.com/knative/serving/pkg/apis/serving/v1alpha1" @@ -149,21 +145,3 @@ func WaitForTriggersListState(clients eventingclient.TriggerInterface, inState f return inState(t) }) } - -// WaitForServiceState polls the status of the Service called name from client -// every interval until inState returns `true` indicating it is done, returns an -// error or timeout. desc will be used to name the metric that is emitted to -// track how long it took for name to get into the state checked by inState. -func WaitForServiceState(client v1.ServiceInterface, name string, inState func(r *corev1.Service) (bool, error), desc string) error { - metricName := fmt.Sprintf("WaitForServiceState/%s/%s", name, desc) - _, span := trace.StartSpan(context.Background(), metricName) - defer span.End() - - return wait.PollImmediate(interval, timeout, func() (bool, error) { - r, err := client.Get(name, metav1.GetOptions{}) - if err != nil { - return true, err - } - return inState(r) - }) -} From aa60a8a938a94219732b8cc096af5fbf22ce0d7b Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Wed, 20 Feb 2019 23:59:52 -0800 Subject: [PATCH 084/221] Removing ugly structs --- test/crd.go | 6 ++ test/e2e/broker_trigger_test.go | 111 +++++++++++++++++--------------- test/helpers.go | 36 ----------- 3 files changed, 65 insertions(+), 88 deletions(-) delete mode 100644 test/helpers.go diff --git a/test/crd.go b/test/crd.go index 5121cd925a1..af3ac3971c8 100644 --- a/test/crd.go +++ b/test/crd.go @@ -215,6 +215,12 @@ type CloudEvent struct { Encoding string // binary or structured } +// TypeAndSource specifies the type and source of an Event. +type TypeAndSource struct { + Type string + Source string +} + const ( CloudEventEncodingBinary = "binary" CloudEventEncodingStructured = "structured" diff --git a/test/e2e/broker_trigger_test.go b/test/e2e/broker_trigger_test.go index b876156be2d..4ef7188a537 100644 --- a/test/e2e/broker_trigger_test.go +++ b/test/e2e/broker_trigger_test.go @@ -39,14 +39,16 @@ const ( any = v1alpha1.TriggerAnyFilter eventType1 = "type1" eventType2 = "type2" + eventType3 = "type3" eventSource1 = "source1" eventSource2 = "source2" + eventSource3 = "source3" ) // Helper function to create names for different objects (e.g., triggers, services, etc.) -func name(obj, brokerName, eventType, eventSource string) string { +func name(obj, eventType, eventSource string) string { // pod names need to be lowercase. We might have an eventType as Any, that is why we lowercase them. - return strings.ToLower(fmt.Sprintf("%s-%s-%s-%s", obj, brokerName, eventType, eventSource)) + return strings.ToLower(fmt.Sprintf("%s-%s-%s", obj, eventType, eventSource)) } func TestBrokerTrigger(t *testing.T) { @@ -73,7 +75,7 @@ func TestBrokerTrigger(t *testing.T) { // we wait for a few seconds for the broker to get created. // Otherwise, if we try to wait for its Ready status and the namespace controller // didn't actually create it yet, the test will fail. - // TODO improve + // TODO improve this logger.Info("Waiting for default broker creation") time.Sleep(waitForDefaultBrokerCreation) @@ -89,29 +91,22 @@ func TestBrokerTrigger(t *testing.T) { logger.Infof("Default broker ready: %q", defaultBrokerUrl) - // Create sender helpers. - senders := []*test.SenderInfo{ - {ns, defaultBrokerUrl, eventType1, eventSource1}, - {ns, defaultBrokerUrl, eventType1, eventSource2}, - {ns, defaultBrokerUrl, eventType2, eventSource1}, - {ns, defaultBrokerUrl, eventType2, eventSource2}, + eventsToReceive := []test.TypeAndSource{ + {any, any}, + {eventType1, any}, + {any, eventSource1}, + {eventType1, eventSource1}, } - // Create dumper helpers. - dumpers := []*test.DumperInfo{ - {ns, defaultBrokerName, any, any, map[string]string{selectorKey: string(uuid.NewUUID())}, make([]string, 0)}, - {ns, defaultBrokerName, eventType1, any, map[string]string{selectorKey: string(uuid.NewUUID())}, make([]string, 0)}, - {ns, defaultBrokerName, any, eventSource1, map[string]string{selectorKey: string(uuid.NewUUID())}, make([]string, 0)}, - {ns, defaultBrokerName, eventType1, eventSource1, map[string]string{selectorKey: string(uuid.NewUUID())}, make([]string, 0)}, - } + selector := map[string]string{selectorKey: string(uuid.NewUUID())} logger.Info("Creating Subscriber pods") - // Save the references in this map for later use. + // Save the pods references in this map for later use. subscriberPods := make(map[string]*corev1.Pod, 0) - for _, dumper := range dumpers { - subscriberPodName := name("dumper", dumper.Broker, dumper.EventType, dumper.EventSource) - subscriberPod := test.EventLoggerPod(subscriberPodName, dumper.Namespace, dumper.Selector) + for _, event := range eventsToReceive { + subscriberPodName := name("dumper", event.Type, event.Source) + subscriberPod := test.EventLoggerPod(subscriberPodName, ns, selector) if err := CreatePod(clients, subscriberPod, logger, cleaner); err != nil { t.Fatalf("Error creating subscriber pod: %v", err) } @@ -122,7 +117,7 @@ func TestBrokerTrigger(t *testing.T) { logger.Info("Waiting for subscriber pods to become running") - // Wait for all of them to be running. + // Wait for all of the pods in the namespace to become running. if err := WaitForAllPodsRunning(clients, logger, ns); err != nil { t.Fatalf("Error waiting for event logger pod to become running: %v", err) } @@ -131,9 +126,9 @@ func TestBrokerTrigger(t *testing.T) { logger.Info("Creating Subscriber services") - for _, dumper := range dumpers { - subscriberSvcName := name("svc", dumper.Broker, dumper.EventType, dumper.EventSource) - service := test.Service(subscriberSvcName, dumper.Namespace, dumper.Selector) + for _, event := range eventsToReceive { + subscriberSvcName := name("svc", event.Type, event.Source) + service := test.Service(subscriberSvcName, ns, selector) if err := CreateService(clients, service, logger, cleaner); err != nil { t.Fatalf("Error creating subscriber service: %v", err) } @@ -143,11 +138,11 @@ func TestBrokerTrigger(t *testing.T) { logger.Info("Creating Triggers") - for _, dumper := range dumpers { - triggerName := name("trigger", dumper.Broker, dumper.EventType, dumper.EventSource) + for _, event := range eventsToReceive { + triggerName := name("trigger", event.Type, event.Source) // subscriberName should be the same as the subscriberSvc from before. - subscriberName := name("svc", dumper.Broker, dumper.EventType, dumper.EventSource) - trigger := test.Trigger(triggerName, dumper.Namespace, dumper.EventType, dumper.EventSource, dumper.Broker, subscriberName) + subscriberName := name("svc", event.Type, event.Source) + trigger := test.Trigger(triggerName, ns, event.Type, event.Source, defaultBrokerName, subscriberName) err := CreateTrigger(clients, trigger, logger, cleaner) if err != nil { t.Fatalf("Error creating trigger: %v", err) @@ -158,36 +153,52 @@ func TestBrokerTrigger(t *testing.T) { logger.Info("Waiting for triggers to become ready") - // Wait for all of them to be ready. + // Wait for all of the triggers in the namespace to be ready. if err := WaitForAllTriggersReady(clients, logger, ns); err != nil { t.Fatalf("Error waiting for triggers to become ready: %v", err) } logger.Info("Triggers ready") + eventsToSend := []test.TypeAndSource{ + {eventType1, eventSource1}, + {eventType1, eventSource2}, + {eventType1, eventSource3}, + {eventType2, eventSource1}, + {eventType2, eventSource2}, + {eventType2, eventSource3}, + {eventType3, eventSource1}, + {eventType3, eventSource2}, + {eventType3, eventSource3}, + } + logger.Info("Creating event sender pods") - for _, sender := range senders { + // Map to save the expected events per dumper so that we can verify the delivery. + expectedEvents := make(map[string][]string) + for _, eventToSend := range eventsToSend { // Create cloud event. // Using event type and source as part of the body for easier debugging. - body := fmt.Sprintf("Body-%s-%s", sender.EventSource, sender.EventType) + body := fmt.Sprintf("Body-%s-%s", eventToSend.Type, eventToSend.Source) cloudEvent := test.CloudEvent{ - Source: sender.EventSource, - Type: sender.EventType, + Source: eventToSend.Source, + Type: eventToSend.Type, Data: fmt.Sprintf(`{"msg":%q}`, body), Encoding: test.CloudEventEncodingStructured, } // Create sender pod. - senderPodName := name("sender", "", sender.EventType, sender.EventSource) - senderPod := test.EventSenderPod(senderPodName, sender.Namespace, sender.Url, cloudEvent) + senderPodName := name("sender", eventToSend.Type, eventToSend.Source) + senderPod := test.EventSenderPod(senderPodName, ns, defaultBrokerUrl, cloudEvent) if err := CreatePod(clients, senderPod, logger, cleaner); err != nil { t.Fatalf("Error creating event sender pod: %v", err) } - // Check on every dumper whether we should expect this event or not, and add its body if so. - for _, dumper := range dumpers { - if shouldExpectEvent(dumper, sender, logger) { - dumper.Expect = append(dumper.Expect, body) + // Check on every dumper whether we should expect this event or not, and add its body + // to the expectedEvents map if so. + for _, eventToReceive := range eventsToReceive { + if shouldExpectEvent(&eventToSend, &eventToReceive, logger) { + subscriberPodName := name("dumper", eventToReceive.Type, eventToReceive.Source) + expectedEvents[subscriberPodName] = append(expectedEvents[subscriberPodName], body) } } } @@ -205,11 +216,11 @@ func TestBrokerTrigger(t *testing.T) { logger.Info("Verifying events delivered to appropriate dumpers") - for _, dumper := range dumpers { - subscriberPodName := name("dumper", dumper.Broker, dumper.EventType, dumper.EventSource) + for _, event := range eventsToReceive { + subscriberPodName := name("dumper", event.Type, event.Source) subscriberPod := subscriberPods[subscriberPodName] - logger.Infof("Dumper %q expecting %q", subscriberPodName, strings.Join(dumper.Expect, ",")) - if err := WaitForLogContents(clients, logger, subscriberPodName, subscriberPod.Spec.Containers[0].Name, dumper.Namespace, dumper.Expect); err != nil { + logger.Infof("Dumper %q expecting %q", subscriberPodName, strings.Join(expectedEvents[subscriberPodName], ",")) + if err := WaitForLogContents(clients, logger, subscriberPodName, subscriberPod.Spec.Containers[0].Name, ns, expectedEvents[subscriberPodName]); err != nil { t.Fatalf("String(s) not found in logs of subscriber pod %q: %v", subscriberPodName, err) } } @@ -218,17 +229,13 @@ func TestBrokerTrigger(t *testing.T) { } -func shouldExpectEvent(dumper *test.DumperInfo, sender *test.SenderInfo, logger *logging.BaseLogger) bool { - if dumper.Namespace != sender.Namespace { - logger.Debugf("Namespaces mismatch, dumper %s, sender %s", dumper.Namespace, sender.Namespace) - return false - } - if dumper.EventType != any && dumper.EventType != sender.EventType { - logger.Debugf("Event types mismatch, dumper %s, sender %s", dumper.EventType, sender.EventType) +func shouldExpectEvent(eventToSend *test.TypeAndSource, eventToReceive *test.TypeAndSource, logger *logging.BaseLogger) bool { + if eventToReceive.Type != any && eventToReceive.Type != eventToSend.Type { + logger.Debugf("Event types mismatch, receive %s, send %s", eventToReceive.Type, eventToSend.Type) return false } - if dumper.EventSource != any && dumper.EventSource != sender.EventSource { - logger.Debugf("Event sources mismatch, dumper %s, sender %s", dumper.EventSource, sender.EventSource) + if eventToReceive.Source != any && eventToReceive.Source != eventToSend.Source { + logger.Debugf("Event sources mismatch, receive %s, send %s", eventToReceive.Source, eventToSend.Source) return false } return true diff --git a/test/helpers.go b/test/helpers.go deleted file mode 100644 index d6e283cb87e..00000000000 --- a/test/helpers.go +++ /dev/null @@ -1,36 +0,0 @@ -/* -Copyright 2019 The Knative Authors -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT 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 test - -// Helper struct to easily create subscriber pods, services and triggers. -// We also use this to verify the expected events that should be received -// by the particular subscriber pods. -type DumperInfo struct { - Namespace string - Broker string - EventType string - EventSource string - Selector map[string]string - Expect []string -} - -// Helper struct to easily create event sender pods. -type SenderInfo struct { - Namespace string - Url string - EventType string - EventSource string -} From 6471b4f2153a048352af8cec23b50735ccfa67c7 Mon Sep 17 00:00:00 2001 From: nachocano Date: Thu, 21 Feb 2019 10:32:42 -0800 Subject: [PATCH 085/221] More logs --- test/e2e/broker_trigger_test.go | 6 ++++-- test/e2e/e2e.go | 3 +++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/test/e2e/broker_trigger_test.go b/test/e2e/broker_trigger_test.go index 4ef7188a537..15244cba36d 100644 --- a/test/e2e/broker_trigger_test.go +++ b/test/e2e/broker_trigger_test.go @@ -51,8 +51,8 @@ func name(obj, eventType, eventSource string) string { return strings.ToLower(fmt.Sprintf("%s-%s-%s", obj, eventType, eventSource)) } -func TestBrokerTrigger(t *testing.T) { - logger := logging.GetContextLogger("TestBrokerTrigger") +func TestDefaultBrokerWithManyTriggers(t *testing.T) { + logger := logging.GetContextLogger("TestDefaultBrokerWithManyTriggers") clients, cleaner := Setup(t, logger) defer TearDown(clients, cleaner, logger) @@ -91,6 +91,7 @@ func TestBrokerTrigger(t *testing.T) { logger.Infof("Default broker ready: %q", defaultBrokerUrl) + // These are the event types and sources that triggers will listen to. eventsToReceive := []test.TypeAndSource{ {any, any}, {eventType1, any}, @@ -160,6 +161,7 @@ func TestBrokerTrigger(t *testing.T) { logger.Info("Triggers ready") + // These are the event types and sources that will be send. eventsToSend := []test.TypeAndSource{ {eventType1, eventSource1}, {eventType1, eventSource2}, diff --git a/test/e2e/e2e.go b/test/e2e/e2e.go index 4972f02eb75..8aac5228087 100644 --- a/test/e2e/e2e.go +++ b/test/e2e/e2e.go @@ -343,6 +343,9 @@ func WaitForLogContents(clients *test.Clients, logger *logging.BaseLogger, podNa if !strings.Contains(string(logs), content) { logger.Infof("Could not find content %q for %s/%s. Found %q instead", content, podName, containerName, string(logs)) return false, nil + } else { + logger.Infof("Found content %q for %s/%s in logs %q", content, podName, containerName, string(logs)) + // do not return as we will keep on looking for the other contents in the slice } } return true, nil From c4959e213aa0ee481eedfe8ddbed6304e5eb21e9 Mon Sep 17 00:00:00 2001 From: nachocano Date: Thu, 21 Feb 2019 14:22:27 -0800 Subject: [PATCH 086/221] Removing quotes --- pkg/broker/receiver.go | 5 +- .../v1alpha1/namespace/namespace.go | 51 +++++++++---------- test/crd.go | 6 +-- 3 files changed, 30 insertions(+), 32 deletions(-) diff --git a/pkg/broker/receiver.go b/pkg/broker/receiver.go index 9dd264337ee..93ada7417d3 100644 --- a/pkg/broker/receiver.go +++ b/pkg/broker/receiver.go @@ -98,18 +98,19 @@ func (r *Receiver) getTrigger(ctx context.Context, ref provisioners.ChannelRefer } func (r *Receiver) shouldSendMessage(ts *eventingv1alpha1.TriggerSpec, m *provisioners.Message) bool { + r.logger.Debug("Message headers", zap.Any("headers", m.Headers)) if ts.Filter == nil || ts.Filter.SourceAndType == nil { r.logger.Error("No filter specified") return false } filterType := ts.Filter.SourceAndType.Type if filterType != eventingv1alpha1.TriggerAnyFilter && filterType != m.Headers["Ce-Eventtype"] { - r.logger.Debug("Wrong type", zap.String("trigger.spec.filter.exactMatch.type", filterType), zap.String("message.type", m.Headers["Ce-Eventtype"])) + r.logger.Debug("Wrong type", zap.String("trigger.spec.filter.sourceAndType.type", filterType), zap.String("message.type", m.Headers["Ce-Eventtype"])) return false } filterSource := ts.Filter.SourceAndType.Source if filterSource != eventingv1alpha1.TriggerAnyFilter && filterSource != m.Headers["Ce-Source"] { - r.logger.Debug("Wrong source", zap.String("trigger.spec.filter.exactMatch.source", filterSource), zap.String("message.source", m.Headers["Ce-Source"])) + r.logger.Debug("Wrong source", zap.String("trigger.spec.filter.sourceAndType.source", filterSource), zap.String("message.source", m.Headers["Ce-Source"])) return false } return true diff --git a/pkg/reconciler/v1alpha1/namespace/namespace.go b/pkg/reconciler/v1alpha1/namespace/namespace.go index 483d659604d..e0c874b80b6 100644 --- a/pkg/reconciler/v1alpha1/namespace/namespace.go +++ b/pkg/reconciler/v1alpha1/namespace/namespace.go @@ -19,11 +19,12 @@ package namespace import ( "context" "fmt" + "github.com/knative/eventing/contrib/gcppubsub/pkg/util/logging" "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" "go.uber.org/zap" - "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1" + v1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" "k8s.io/apimachinery/pkg/api/errors" k8serrors "k8s.io/apimachinery/pkg/api/errors" @@ -46,16 +47,16 @@ const ( // itself when creating events. controllerAgentName = "knative-eventing-namespace-controller" - defaultBroker = "default" - brokerFilterSA = "eventing-broker-filter" - brokerFilterRB = "eventing-broker-filter" + defaultBroker = "default" + brokerFilterSA = "eventing-broker-filter" + brokerFilterRB = "eventing-broker-filter" brokerFilterClusterRole = "eventing-broker-filter" knativeEventingAnnotation = "eventing.knative.dev/inject" // Name of the corev1.Events emitted from the reconciliation process. - brokerCreated = "BrokerCreated" - serviceAccountCreated = "BrokerFilterServiceAccountCreated" + brokerCreated = "BrokerCreated" + serviceAccountCreated = "BrokerFilterServiceAccountCreated" serviceAccountRBACCreated = "BrokerFilterServiceAccountRBACCreated" ) @@ -92,8 +93,8 @@ func ProvideController(logger *zap.Logger) func(manager.Manager) (controller.Con } // Watch all the resources that this reconciler reconciles. - for _, t := range []runtime.Object{ &corev1.ServiceAccount{}, &rbacv1.RoleBinding{}, &v1alpha1.Broker{} } { - err = c.Watch(&source.Kind{Type: t}, &handler.EnqueueRequestsFromMapFunc{ToRequests: &namespaceMapper{}}); + for _, t := range []runtime.Object{&corev1.ServiceAccount{}, &rbacv1.RoleBinding{}, &v1alpha1.Broker{}} { + err = c.Watch(&source.Kind{Type: t}, &handler.EnqueueRequestsFromMapFunc{ToRequests: &namespaceMapper{}}) if err != nil { return nil, err } @@ -228,8 +229,8 @@ func newBrokerFilterServiceAccount(ns *corev1.Namespace) *corev1.ServiceAccount return &corev1.ServiceAccount{ ObjectMeta: metav1.ObjectMeta{ Namespace: ns.Name, - Name: brokerFilterSA, - Labels: injectedLabels(), + Name: brokerFilterSA, + Labels: injectedLabels(), }, } } @@ -240,7 +241,7 @@ func injectedLabels() map[string]string { } } -func (r *reconciler) reconcileBrokerFilterRBAC(ctx context.Context, ns *corev1.Namespace, sa *corev1.ServiceAccount) (*rbacv1.RoleBinding, error) { +func (r *reconciler) reconcileBrokerFilterRBAC(ctx context.Context, ns *corev1.Namespace, sa *corev1.ServiceAccount) (*rbacv1.ClusterRoleBinding, error) { current, err := r.getBrokerFilterRBAC(ctx, ns) // If the resource doesn't exist, we'll create it. @@ -262,33 +263,31 @@ func (r *reconciler) reconcileBrokerFilterRBAC(ctx context.Context, ns *corev1.N return current, nil } -func (r *reconciler) getBrokerFilterRBAC(ctx context.Context, ns *corev1.Namespace) (*rbacv1.RoleBinding, error) { - rb := &rbacv1.RoleBinding{} +func (r *reconciler) getBrokerFilterRBAC(ctx context.Context, ns *corev1.Namespace) (*rbacv1.ClusterRoleBinding, error) { + rb := &rbacv1.ClusterRoleBinding{} name := types.NamespacedName{ - Namespace: ns.Name, - Name: brokerFilterRB, + Name: brokerFilterRB, } err := r.client.Get(ctx, name, rb) return rb, err } -func newBrokerFilterRBAC(ns *corev1.Namespace, sa *corev1.ServiceAccount) *rbacv1.RoleBinding { - return &rbacv1.RoleBinding{ +func newBrokerFilterRBAC(ns *corev1.Namespace, sa *corev1.ServiceAccount) *rbacv1.ClusterRoleBinding { + return &rbacv1.ClusterRoleBinding{ ObjectMeta: metav1.ObjectMeta{ - Namespace: ns.Name, - Name: brokerFilterRB, + Name: brokerFilterRB, Labels: injectedLabels(), }, - RoleRef:rbacv1.RoleRef{ - APIGroup:"rbac.authorization.k8s.io", - Kind: "ClusterRole", - Name: brokerFilterClusterRole, + RoleRef: rbacv1.RoleRef{ + APIGroup: "rbac.authorization.k8s.io", + Kind: "ClusterRole", + Name: brokerFilterClusterRole, }, - Subjects:[]rbacv1.Subject{ + Subjects: []rbacv1.Subject{ { - Kind: "ServiceAccount", + Kind: "ServiceAccount", Namespace: ns.Name, - Name: sa.Name, + Name: sa.Name, }, }, } diff --git a/test/crd.go b/test/crd.go index af3ac3971c8..1e7ff0760c6 100644 --- a/test/crd.go +++ b/test/crd.go @@ -18,8 +18,6 @@ package test // crd contains functions that construct boilerplate CRD definitions. import ( - "fmt" - "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" servingv1alpha1 "github.com/knative/serving/pkg/apis/serving/v1alpha1" corev1 "k8s.io/api/core/v1" @@ -190,8 +188,8 @@ func Trigger(name, namespace, eventType, eventSource, broker, svcName string) *v Broker: broker, Filter: &v1alpha1.TriggerFilter{ SourceAndType: &v1alpha1.TriggerFilterSourceAndType{ - Type: fmt.Sprintf("%q", eventType), - Source: fmt.Sprintf("%q", eventSource), + Type: eventType, + Source: eventSource, }, }, Subscriber: &v1alpha1.SubscriberSpec{ From 69ebf1857071dd43a193a2e62fa8f4df9b5ef8f8 Mon Sep 17 00:00:00 2001 From: nachocano Date: Thu, 21 Feb 2019 14:51:27 -0800 Subject: [PATCH 087/221] More logs --- pkg/broker/receiver.go | 1 - test/e2e/broker_trigger_test.go | 14 +++----------- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/pkg/broker/receiver.go b/pkg/broker/receiver.go index 93ada7417d3..14ca97b0d5a 100644 --- a/pkg/broker/receiver.go +++ b/pkg/broker/receiver.go @@ -98,7 +98,6 @@ func (r *Receiver) getTrigger(ctx context.Context, ref provisioners.ChannelRefer } func (r *Receiver) shouldSendMessage(ts *eventingv1alpha1.TriggerSpec, m *provisioners.Message) bool { - r.logger.Debug("Message headers", zap.Any("headers", m.Headers)) if ts.Filter == nil || ts.Filter.SourceAndType == nil { r.logger.Error("No filter specified") return false diff --git a/test/e2e/broker_trigger_test.go b/test/e2e/broker_trigger_test.go index 15244cba36d..49358512eac 100644 --- a/test/e2e/broker_trigger_test.go +++ b/test/e2e/broker_trigger_test.go @@ -39,10 +39,8 @@ const ( any = v1alpha1.TriggerAnyFilter eventType1 = "type1" eventType2 = "type2" - eventType3 = "type3" eventSource1 = "source1" eventSource2 = "source2" - eventSource3 = "source3" ) // Helper function to create names for different objects (e.g., triggers, services, etc.) @@ -165,13 +163,8 @@ func TestDefaultBrokerWithManyTriggers(t *testing.T) { eventsToSend := []test.TypeAndSource{ {eventType1, eventSource1}, {eventType1, eventSource2}, - {eventType1, eventSource3}, {eventType2, eventSource1}, {eventType2, eventSource2}, - {eventType2, eventSource3}, - {eventType3, eventSource1}, - {eventType3, eventSource2}, - {eventType3, eventSource3}, } logger.Info("Creating event sender pods") @@ -183,10 +176,9 @@ func TestDefaultBrokerWithManyTriggers(t *testing.T) { // Using event type and source as part of the body for easier debugging. body := fmt.Sprintf("Body-%s-%s", eventToSend.Type, eventToSend.Source) cloudEvent := test.CloudEvent{ - Source: eventToSend.Source, - Type: eventToSend.Type, - Data: fmt.Sprintf(`{"msg":%q}`, body), - Encoding: test.CloudEventEncodingStructured, + Source: eventToSend.Source, + Type: eventToSend.Type, + Data: fmt.Sprintf(`{"msg":%q}`, body), } // Create sender pod. senderPodName := name("sender", eventToSend.Type, eventToSend.Source) From 1dccad8dc007f143c26c94e4f3101285214a333f Mon Sep 17 00:00:00 2001 From: nachocano Date: Thu, 21 Feb 2019 15:35:57 -0800 Subject: [PATCH 088/221] Adding delay --- test/crd.go | 9 +++++++++ test/e2e/broker_trigger_test.go | 3 ++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/test/crd.go b/test/crd.go index 1e7ff0760c6..e68d26933d8 100644 --- a/test/crd.go +++ b/test/crd.go @@ -226,6 +226,13 @@ const ( // EventSenderPod creates a Pod that sends a single event to the given address. func EventSenderPod(name string, namespace string, sink string, event CloudEvent) *corev1.Pod { + // By setting delay to an invalid integer (i.e., default), + // the event sender pod will end up using its default one. + return EventSenderPodWithDelay(name, namespace, sink, "default", event) +} + +// EventSenderPod creates a Pod that sends a single event to the given address with a given delay. +func EventSenderPodWithDelay(name string, namespace string, sink string, delay string, event CloudEvent) *corev1.Pod { if event.Encoding == "" { event.Encoding = CloudEventEncodingBinary } @@ -254,6 +261,8 @@ func EventSenderPod(name string, namespace string, sink string, event CloudEvent event.Encoding, "-sink", sink, + "-delay", + delay, }, }}, //TODO restart on failure? diff --git a/test/e2e/broker_trigger_test.go b/test/e2e/broker_trigger_test.go index 49358512eac..99f704ee722 100644 --- a/test/e2e/broker_trigger_test.go +++ b/test/e2e/broker_trigger_test.go @@ -34,6 +34,7 @@ import ( const ( defaultBrokerName = "default" waitForDefaultBrokerCreation = 3 * time.Second + sendEventDelay = "15" selectorKey = "end2end-test-broker-trigger" any = v1alpha1.TriggerAnyFilter @@ -182,7 +183,7 @@ func TestDefaultBrokerWithManyTriggers(t *testing.T) { } // Create sender pod. senderPodName := name("sender", eventToSend.Type, eventToSend.Source) - senderPod := test.EventSenderPod(senderPodName, ns, defaultBrokerUrl, cloudEvent) + senderPod := test.EventSenderPodWithDelay(senderPodName, ns, defaultBrokerUrl, sendEventDelay, cloudEvent) if err := CreatePod(clients, senderPod, logger, cleaner); err != nil { t.Fatalf("Error creating event sender pod: %v", err) } From 2b67eb8b2e8df3e33d980741313c1b46fc65957e Mon Sep 17 00:00:00 2001 From: nachocano Date: Thu, 21 Feb 2019 17:30:57 -0800 Subject: [PATCH 089/221] Listing triggers in receiver when we create it, so that we don't miss any message because the client couldn't find the existing trigger. This is a problem in the in-memory-channel as it doesn't do retries. Maybe the right solution is to add that functionality there. --- pkg/broker/receiver.go | 32 ++++++++++++++++++++++++++++++++ test/e2e/broker_trigger_test.go | 29 ++++++++++++++++++----------- 2 files changed, 50 insertions(+), 11 deletions(-) diff --git a/pkg/broker/receiver.go b/pkg/broker/receiver.go index 14ca97b0d5a..5998b63bd40 100644 --- a/pkg/broker/receiver.go +++ b/pkg/broker/receiver.go @@ -23,6 +23,7 @@ import ( eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" "github.com/knative/eventing/pkg/provisioners" "go.uber.org/zap" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/manager" @@ -48,6 +49,10 @@ func New(logger *zap.Logger, client client.Client) (*Receiver, manager.Runnable) } func (r *Receiver) newMessageReceiver() *provisioners.MessageReceiver { + err := r.initClient() + if err != nil { + r.logger.Warn("Failed to initialize client", zap.Error(err)) + } return provisioners.NewMessageReceiver(r.sendEvent, r.logger.Sugar()) } @@ -82,6 +87,33 @@ func (r *Receiver) sendEvent(channel provisioners.ChannelReference, message *pro return nil } +// Initialize the client. Mainly intended to load stuff in its cache. +func (r *Receiver) initClient() error { + // We list triggers so that we can load the client's cache. + // Otherwise, on receiving an event, it may not find the trigger + // and would return an error. + opts := &client.ListOptions{ + Raw: &metav1.ListOptions{ + TypeMeta: metav1.TypeMeta{ + APIVersion: eventingv1alpha1.SchemeGroupVersion.String(), + Kind: "Trigger", + }, + }, + } + for { + tl := &eventingv1alpha1.TriggerList{} + if err := r.client.List(context.TODO(), opts, tl); err != nil { + return err + } + if tl.Continue != "" { + opts.Raw.Continue = tl.Continue + } else { + break + } + } + return nil +} + func (r *Receiver) getTrigger(ctx context.Context, ref provisioners.ChannelReference) (*eventingv1alpha1.Trigger, error) { // Sadly this doesn't work well because we do not yet have // https://github.com/kubernetes-sigs/controller-runtime/pull/136, so controller runtime watches diff --git a/test/e2e/broker_trigger_test.go b/test/e2e/broker_trigger_test.go index 99f704ee722..695663ae72e 100644 --- a/test/e2e/broker_trigger_test.go +++ b/test/e2e/broker_trigger_test.go @@ -44,12 +44,6 @@ const ( eventSource2 = "source2" ) -// Helper function to create names for different objects (e.g., triggers, services, etc.) -func name(obj, eventType, eventSource string) string { - // pod names need to be lowercase. We might have an eventType as Any, that is why we lowercase them. - return strings.ToLower(fmt.Sprintf("%s-%s-%s", obj, eventType, eventSource)) -} - func TestDefaultBrokerWithManyTriggers(t *testing.T) { logger := logging.GetContextLogger("TestDefaultBrokerWithManyTriggers") @@ -98,15 +92,16 @@ func TestDefaultBrokerWithManyTriggers(t *testing.T) { {eventType1, eventSource1}, } - selector := map[string]string{selectorKey: string(uuid.NewUUID())} + // Create one selector for each subscriberPod and service + selectors := []map[string]string{newSelector(), newSelector(), newSelector(), newSelector()} logger.Info("Creating Subscriber pods") // Save the pods references in this map for later use. subscriberPods := make(map[string]*corev1.Pod, 0) - for _, event := range eventsToReceive { + for i, event := range eventsToReceive { subscriberPodName := name("dumper", event.Type, event.Source) - subscriberPod := test.EventLoggerPod(subscriberPodName, ns, selector) + subscriberPod := test.EventLoggerPod(subscriberPodName, ns, selectors[i]) if err := CreatePod(clients, subscriberPod, logger, cleaner); err != nil { t.Fatalf("Error creating subscriber pod: %v", err) } @@ -126,9 +121,9 @@ func TestDefaultBrokerWithManyTriggers(t *testing.T) { logger.Info("Creating Subscriber services") - for _, event := range eventsToReceive { + for i, event := range eventsToReceive { subscriberSvcName := name("svc", event.Type, event.Source) - service := test.Service(subscriberSvcName, ns, selector) + service := test.Service(subscriberSvcName, ns, selectors[i]) if err := CreateService(clients, service, logger, cleaner); err != nil { t.Fatalf("Error creating subscriber service: %v", err) } @@ -224,6 +219,18 @@ func TestDefaultBrokerWithManyTriggers(t *testing.T) { } +// Helper function to create names for different objects (e.g., triggers, services, etc.) +func name(obj, eventType, eventSource string) string { + // pod names need to be lowercase. We might have an eventType as Any, that is why we lowercase them. + return strings.ToLower(fmt.Sprintf("%s-%s-%s", obj, eventType, eventSource)) +} + +// Returns a new selector with a random uuid. +func newSelector() map[string]string { + return map[string]string{selectorKey: string(uuid.NewUUID())} +} + +// Checks whether we should expect to receive 'eventToSend' based on 'eventToReceive' filter pattern. func shouldExpectEvent(eventToSend *test.TypeAndSource, eventToReceive *test.TypeAndSource, logger *logging.BaseLogger) bool { if eventToReceive.Type != any && eventToReceive.Type != eventToSend.Type { logger.Debugf("Event types mismatch, receive %s, send %s", eventToReceive.Type, eventToSend.Type) From a44d6d28df16cbb110db786fdf975c654fa08eb4 Mon Sep 17 00:00:00 2001 From: nachocano Date: Thu, 21 Feb 2019 17:51:02 -0800 Subject: [PATCH 090/221] Adding delay to sender pod --- test/e2e/broker_trigger_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/e2e/broker_trigger_test.go b/test/e2e/broker_trigger_test.go index 695663ae72e..6fba925fe9a 100644 --- a/test/e2e/broker_trigger_test.go +++ b/test/e2e/broker_trigger_test.go @@ -33,8 +33,8 @@ import ( const ( defaultBrokerName = "default" - waitForDefaultBrokerCreation = 3 * time.Second - sendEventDelay = "15" + waitForDefaultBrokerCreation = 5 * time.Second + senderPodDelay = 15 selectorKey = "end2end-test-broker-trigger" any = v1alpha1.TriggerAnyFilter @@ -178,7 +178,7 @@ func TestDefaultBrokerWithManyTriggers(t *testing.T) { } // Create sender pod. senderPodName := name("sender", eventToSend.Type, eventToSend.Source) - senderPod := test.EventSenderPodWithDelay(senderPodName, ns, defaultBrokerUrl, sendEventDelay, cloudEvent) + senderPod := test.EventSenderPodWithDelay(senderPodName, ns, defaultBrokerUrl, string(senderPodDelay), cloudEvent) if err := CreatePod(clients, senderPod, logger, cleaner); err != nil { t.Fatalf("Error creating event sender pod: %v", err) } From 41ab0a82370117ceac049087a03f1198504edd3a Mon Sep 17 00:00:00 2001 From: nachocano Date: Thu, 21 Feb 2019 18:07:22 -0800 Subject: [PATCH 091/221] Removing withDelay method and just sleep for a while --- test/crd.go | 9 --------- test/e2e/broker_trigger_test.go | 10 ++++++++-- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/test/crd.go b/test/crd.go index e68d26933d8..1e7ff0760c6 100644 --- a/test/crd.go +++ b/test/crd.go @@ -226,13 +226,6 @@ const ( // EventSenderPod creates a Pod that sends a single event to the given address. func EventSenderPod(name string, namespace string, sink string, event CloudEvent) *corev1.Pod { - // By setting delay to an invalid integer (i.e., default), - // the event sender pod will end up using its default one. - return EventSenderPodWithDelay(name, namespace, sink, "default", event) -} - -// EventSenderPod creates a Pod that sends a single event to the given address with a given delay. -func EventSenderPodWithDelay(name string, namespace string, sink string, delay string, event CloudEvent) *corev1.Pod { if event.Encoding == "" { event.Encoding = CloudEventEncodingBinary } @@ -261,8 +254,6 @@ func EventSenderPodWithDelay(name string, namespace string, sink string, delay s event.Encoding, "-sink", sink, - "-delay", - delay, }, }}, //TODO restart on failure? diff --git a/test/e2e/broker_trigger_test.go b/test/e2e/broker_trigger_test.go index 6fba925fe9a..651733defbf 100644 --- a/test/e2e/broker_trigger_test.go +++ b/test/e2e/broker_trigger_test.go @@ -34,7 +34,7 @@ import ( const ( defaultBrokerName = "default" waitForDefaultBrokerCreation = 5 * time.Second - senderPodDelay = 15 + waitForFilterPodRunning = 30 * time.Second selectorKey = "end2end-test-broker-trigger" any = v1alpha1.TriggerAnyFilter @@ -163,6 +163,12 @@ func TestDefaultBrokerWithManyTriggers(t *testing.T) { {eventType2, eventSource2}, } + // We notice few crashLoopBacks in the filter pod creation. + // We then delay the creation of the sender pods to not miss events. + // TODO improve this + logger.Info("Waiting for filter pod up and running") + time.Sleep(waitForFilterPodRunning) + logger.Info("Creating event sender pods") // Map to save the expected events per dumper so that we can verify the delivery. @@ -178,7 +184,7 @@ func TestDefaultBrokerWithManyTriggers(t *testing.T) { } // Create sender pod. senderPodName := name("sender", eventToSend.Type, eventToSend.Source) - senderPod := test.EventSenderPodWithDelay(senderPodName, ns, defaultBrokerUrl, string(senderPodDelay), cloudEvent) + senderPod := test.EventSenderPod(senderPodName, ns, defaultBrokerUrl, cloudEvent) if err := CreatePod(clients, senderPod, logger, cleaner); err != nil { t.Fatalf("Error creating event sender pod: %v", err) } From 6a832eaa28a4d136953399e85abd7d4d8be32705 Mon Sep 17 00:00:00 2001 From: nachocano Date: Thu, 21 Feb 2019 18:13:07 -0800 Subject: [PATCH 092/221] Improve log... --- test/e2e/broker_trigger_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/e2e/broker_trigger_test.go b/test/e2e/broker_trigger_test.go index 651733defbf..d472dd293d3 100644 --- a/test/e2e/broker_trigger_test.go +++ b/test/e2e/broker_trigger_test.go @@ -163,10 +163,10 @@ func TestDefaultBrokerWithManyTriggers(t *testing.T) { {eventType2, eventSource2}, } - // We notice few crashLoopBacks in the filter pod creation. - // We then delay the creation of the sender pods to not miss events. + // We notice some crashLoopBacks in the filter and ingress pod creation. + // We then delay the creation of the sender pods in order not to miss events. // TODO improve this - logger.Info("Waiting for filter pod up and running") + logger.Info("Waiting for filter and ingress pods to become running") time.Sleep(waitForFilterPodRunning) logger.Info("Creating event sender pods") From 446022aa784cd22d69ac910a90aa3ac9d32bb091 Mon Sep 17 00:00:00 2001 From: nachocano Date: Fri, 22 Feb 2019 17:02:52 -0800 Subject: [PATCH 093/221] Updates after code review. --- test/builders.go | 79 +++++++++++++++++++++++ test/crd.go | 26 -------- test/crd_checks.go | 8 ++- test/e2e/broker_trigger_test.go | 108 +++++++++++++++++++------------- test/e2e/e2e.go | 26 ++++++-- 5 files changed, 170 insertions(+), 77 deletions(-) create mode 100644 test/builders.go diff --git a/test/builders.go b/test/builders.go new file mode 100644 index 00000000000..3de022ad65e --- /dev/null +++ b/test/builders.go @@ -0,0 +1,79 @@ +/* +Copyright 2019 The Knative Authors +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT 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 test + +import ( + eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +type TriggerBuilder struct { + *eventingv1alpha1.Trigger +} + +func NewTriggerBuilder(name, namespace string) *TriggerBuilder { + trigger := &eventingv1alpha1.Trigger{ + TypeMeta: metav1.TypeMeta{ + APIVersion: eventingv1alpha1.SchemeGroupVersion.String(), + Kind: "Trigger", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + }, + Spec: eventingv1alpha1.TriggerSpec{ + Broker: "default", + Filter: &eventingv1alpha1.TriggerFilter{ + SourceAndType: &eventingv1alpha1.TriggerFilterSourceAndType{ + Type: eventingv1alpha1.TriggerAnyFilter, + Source: eventingv1alpha1.TriggerAnyFilter, + }, + }, + Subscriber: &eventingv1alpha1.SubscriberSpec{}, + }, + } + + return &TriggerBuilder{ + Trigger: trigger, + } +} + +func (b *TriggerBuilder) Build() *eventingv1alpha1.Trigger { + return b.Trigger.DeepCopy() +} + +func (b *TriggerBuilder) EventType(eventType string) *TriggerBuilder { + b.Trigger.Spec.Filter.SourceAndType.Type = eventType + return b +} + +func (b *TriggerBuilder) EventSource(eventType string) *TriggerBuilder { + b.Trigger.Spec.Filter.SourceAndType.Type = eventType + return b +} + +func (b *TriggerBuilder) Broker(brokerName string) *TriggerBuilder { + b.Trigger.Spec.Broker = brokerName + return b +} + +func (b *TriggerBuilder) SubscriberSvc(svcName string) *TriggerBuilder { + b.Trigger.Spec.Subscriber.Ref = &corev1.ObjectReference{ + APIVersion: corev1.SchemeGroupVersion.String(), + Kind: "Service", + Name: svcName, + } + return b +} diff --git a/test/crd.go b/test/crd.go index 1e7ff0760c6..37016def59b 100644 --- a/test/crd.go +++ b/test/crd.go @@ -177,32 +177,6 @@ func Broker(name string, namespace string) *v1alpha1.Broker { } } -// Trigger returns a Trigger. -func Trigger(name, namespace, eventType, eventSource, broker, svcName string) *v1alpha1.Trigger { - return &v1alpha1.Trigger{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: namespace, - }, - Spec: v1alpha1.TriggerSpec{ - Broker: broker, - Filter: &v1alpha1.TriggerFilter{ - SourceAndType: &v1alpha1.TriggerFilterSourceAndType{ - Type: eventType, - Source: eventSource, - }, - }, - Subscriber: &v1alpha1.SubscriberSpec{ - Ref: &corev1.ObjectReference{ - APIVersion: "v1", - Kind: "Service", - Name: svcName, - }, - }, - }, - } -} - // CloudEvent specifies the arguments for a CloudEvent sent by the sendevent // binary. type CloudEvent struct { diff --git a/test/crd_checks.go b/test/crd_checks.go index faebe200ed4..ab933bd394b 100644 --- a/test/crd_checks.go +++ b/test/crd_checks.go @@ -28,6 +28,7 @@ import ( servingv1alpha1 "github.com/knative/serving/pkg/apis/serving/v1alpha1" servingclient "github.com/knative/serving/pkg/client/clientset/versioned/typed/serving/v1alpha1" "go.opencensus.io/trace" + k8serrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/wait" ) @@ -103,7 +104,12 @@ func WaitForBrokerState(client eventingclient.BrokerInterface, name string, inSt return wait.PollImmediate(interval, timeout, func() (bool, error) { r, err := client.Get(name, metav1.GetOptions{}) - if err != nil { + if k8serrors.IsNotFound(err) { + // Return false as we are not done yet. + // We swallow the error to keep on polling + return false, nil + } else if err != nil { + // Return true to stop and return the error. return true, err } return inState(r) diff --git a/test/e2e/broker_trigger_test.go b/test/e2e/broker_trigger_test.go index d472dd293d3..aa7b674d104 100644 --- a/test/e2e/broker_trigger_test.go +++ b/test/e2e/broker_trigger_test.go @@ -32,10 +32,9 @@ import ( ) const ( - defaultBrokerName = "default" - waitForDefaultBrokerCreation = 5 * time.Second - waitForFilterPodRunning = 30 * time.Second - selectorKey = "end2end-test-broker-trigger" + defaultBrokerName = "default" + waitForFilterPodRunning = 30 * time.Second + selectorKey = "end2end-test-broker-trigger" any = v1alpha1.TriggerAnyFilter eventType1 = "type1" @@ -44,15 +43,27 @@ const ( eventSource2 = "source2" ) +// Helper struct to tie the type and sources of the events we expect to receive +// in subscribers with the selectors we use when creating their pods. +type eventReceiver struct { + typeAndSource test.TypeAndSource + selector map[string]string +} + +// This test annotates the testing namespace so that a default broker is created. +// It then binds many triggers with different filtering patterns to that default broker, +// and sends different events to the broker's address. Finally, it verifies that only +// the appropriate events are routed to the subscribers. func TestDefaultBrokerWithManyTriggers(t *testing.T) { logger := logging.GetContextLogger("TestDefaultBrokerWithManyTriggers") clients, cleaner := Setup(t, logger) - defer TearDown(clients, cleaner, logger) // Verify namespace exists. ns, cleanupNS := NamespaceExists(t, clients, logger) + defer cleanupNS() + defer TearDown(clients, cleaner, logger) logger.Infof("Annotating namespace %s", ns) @@ -64,14 +75,6 @@ func TestDefaultBrokerWithManyTriggers(t *testing.T) { logger.Infof("Namespace %s annotated", ns) - // As we are not creating the default broker, - // we wait for a few seconds for the broker to get created. - // Otherwise, if we try to wait for its Ready status and the namespace controller - // didn't actually create it yet, the test will fail. - // TODO improve this - logger.Info("Waiting for default broker creation") - time.Sleep(waitForDefaultBrokerCreation) - // Wait for default broker ready. logger.Info("Waiting for default broker to be ready") defaultBroker := test.Broker(defaultBrokerName, ns) @@ -84,24 +87,22 @@ func TestDefaultBrokerWithManyTriggers(t *testing.T) { logger.Infof("Default broker ready: %q", defaultBrokerUrl) - // These are the event types and sources that triggers will listen to. - eventsToReceive := []test.TypeAndSource{ - {any, any}, - {eventType1, any}, - {any, eventSource1}, - {eventType1, eventSource1}, + // These are the event types and sources that triggers will listen to, as well as the selectors + // to set in the subscriber and services pods. + eventsToReceive := []eventReceiver{ + {test.TypeAndSource{Type: any, Source: any}, newSelector()}, + {test.TypeAndSource{Type: eventType1, Source: any}, newSelector()}, + {test.TypeAndSource{Type: any, Source: eventSource1}, newSelector()}, + {test.TypeAndSource{Type: eventType1, Source: eventSource1}, newSelector()}, } - // Create one selector for each subscriberPod and service - selectors := []map[string]string{newSelector(), newSelector(), newSelector(), newSelector()} - logger.Info("Creating Subscriber pods") // Save the pods references in this map for later use. - subscriberPods := make(map[string]*corev1.Pod, 0) - for i, event := range eventsToReceive { - subscriberPodName := name("dumper", event.Type, event.Source) - subscriberPod := test.EventLoggerPod(subscriberPodName, ns, selectors[i]) + subscriberPods := make(map[string]*corev1.Pod, len(eventsToReceive)) + for _, event := range eventsToReceive { + subscriberPodName := name("dumper", event.typeAndSource.Type, event.typeAndSource.Source) + subscriberPod := test.EventLoggerPod(subscriberPodName, ns, event.selector) if err := CreatePod(clients, subscriberPod, logger, cleaner); err != nil { t.Fatalf("Error creating subscriber pod: %v", err) } @@ -121,9 +122,9 @@ func TestDefaultBrokerWithManyTriggers(t *testing.T) { logger.Info("Creating Subscriber services") - for i, event := range eventsToReceive { - subscriberSvcName := name("svc", event.Type, event.Source) - service := test.Service(subscriberSvcName, ns, selectors[i]) + for _, event := range eventsToReceive { + subscriberSvcName := name("svc", event.typeAndSource.Type, event.typeAndSource.Source) + service := test.Service(subscriberSvcName, ns, event.selector) if err := CreateService(clients, service, logger, cleaner); err != nil { t.Fatalf("Error creating subscriber service: %v", err) } @@ -134,10 +135,17 @@ func TestDefaultBrokerWithManyTriggers(t *testing.T) { logger.Info("Creating Triggers") for _, event := range eventsToReceive { - triggerName := name("trigger", event.Type, event.Source) + triggerName := name("trigger", event.typeAndSource.Type, event.typeAndSource.Source) // subscriberName should be the same as the subscriberSvc from before. - subscriberName := name("svc", event.Type, event.Source) - trigger := test.Trigger(triggerName, ns, event.Type, event.Source, defaultBrokerName, subscriberName) + subscriberName := name("svc", event.typeAndSource.Type, event.typeAndSource.Source) + trigger := test.NewTriggerBuilder(triggerName, ns). + EventType(event.typeAndSource.Type). + EventSource(event.typeAndSource.Source). + // Don't need to set the broker as we use the default one + // but wanted to be more explicit. + Broker(defaultBrokerName). + SubscriberSvc(subscriberName). + Build() err := CreateTrigger(clients, trigger, logger, cleaner) if err != nil { t.Fatalf("Error creating trigger: %v", err) @@ -173,6 +181,8 @@ func TestDefaultBrokerWithManyTriggers(t *testing.T) { // Map to save the expected events per dumper so that we can verify the delivery. expectedEvents := make(map[string][]string) + // Map to save the unexpected events per dumper so that we can verify that they weren't delivered. + unexpectedEvents := make(map[string][]string) for _, eventToSend := range eventsToSend { // Create cloud event. // Using event type and source as part of the body for easier debugging. @@ -190,11 +200,13 @@ func TestDefaultBrokerWithManyTriggers(t *testing.T) { } // Check on every dumper whether we should expect this event or not, and add its body - // to the expectedEvents map if so. + // to the expectedEvents/unexpectedEvents maps. for _, eventToReceive := range eventsToReceive { + subscriberPodName := name("dumper", eventToReceive.typeAndSource.Type, eventToReceive.typeAndSource.Source) if shouldExpectEvent(&eventToSend, &eventToReceive, logger) { - subscriberPodName := name("dumper", eventToReceive.Type, eventToReceive.Source) expectedEvents[subscriberPodName] = append(expectedEvents[subscriberPodName], body) + } else { + unexpectedEvents[subscriberPodName] = append(unexpectedEvents[subscriberPodName], body) } } } @@ -213,16 +225,22 @@ func TestDefaultBrokerWithManyTriggers(t *testing.T) { logger.Info("Verifying events delivered to appropriate dumpers") for _, event := range eventsToReceive { - subscriberPodName := name("dumper", event.Type, event.Source) + subscriberPodName := name("dumper", event.typeAndSource.Type, event.typeAndSource.Source) subscriberPod := subscriberPods[subscriberPodName] logger.Infof("Dumper %q expecting %q", subscriberPodName, strings.Join(expectedEvents[subscriberPodName], ",")) if err := WaitForLogContents(clients, logger, subscriberPodName, subscriberPod.Spec.Containers[0].Name, ns, expectedEvents[subscriberPodName]); err != nil { - t.Fatalf("String(s) not found in logs of subscriber pod %q: %v", subscriberPodName, err) + t.Fatalf("Event(s) not found in logs of subscriber pod %q: %v", subscriberPodName, err) + } + // At this point all the events should have been received in the pod. + // We check whether we find them unexpected events. If so, then we fail. + found, err := FindAnyLogContents(clients, logger, subscriberPodName, subscriberPod.Spec.Containers[0].Name, ns, unexpectedEvents[subscriberPodName]) + if err != nil { + t.Fatalf("Failed querying to find log contents in pod %q: %v", subscriberPodName, err) + } + if found { + t.Fatalf("Unexpected event(s) found in logs of subscriber pod %q", subscriberPodName) } } - - logger.Info("Verification successful!") - } // Helper function to create names for different objects (e.g., triggers, services, etc.) @@ -236,14 +254,14 @@ func newSelector() map[string]string { return map[string]string{selectorKey: string(uuid.NewUUID())} } -// Checks whether we should expect to receive 'eventToSend' based on 'eventToReceive' filter pattern. -func shouldExpectEvent(eventToSend *test.TypeAndSource, eventToReceive *test.TypeAndSource, logger *logging.BaseLogger) bool { - if eventToReceive.Type != any && eventToReceive.Type != eventToSend.Type { - logger.Debugf("Event types mismatch, receive %s, send %s", eventToReceive.Type, eventToSend.Type) +// Checks whether we should expect to receive 'eventToSend' in 'eventReceiver' based on its type and source pattern. +func shouldExpectEvent(eventToSend *test.TypeAndSource, receiver *eventReceiver, logger *logging.BaseLogger) bool { + if receiver.typeAndSource.Type != any && receiver.typeAndSource.Type != eventToSend.Type { + logger.Debugf("Event types mismatch, receive %s, send %s", receiver.typeAndSource.Type, eventToSend.Type) return false } - if eventToReceive.Source != any && eventToReceive.Source != eventToSend.Source { - logger.Debugf("Event sources mismatch, receive %s, send %s", eventToReceive.Source, eventToSend.Source) + if receiver.typeAndSource.Source != any && receiver.typeAndSource.Source != eventToSend.Source { + logger.Debugf("Event sources mismatch, receive %s, send %s", receiver.typeAndSource.Source, eventToSend.Source) return false } return true diff --git a/test/e2e/e2e.go b/test/e2e/e2e.go index 8aac5228087..f81d7452812 100644 --- a/test/e2e/e2e.go +++ b/test/e2e/e2e.go @@ -161,7 +161,7 @@ func WithChannelAndSubscriptionReady(clients *test.Clients, channel *v1alpha1.Ch return nil } -// CreateBroker will create a Broker +// CreateBroker will create a Broker. func CreateBroker(clients *test.Clients, broker *v1alpha1.Broker, logger *logging.BaseLogger, cleaner *test.Cleaner) error { brokers := clients.Eventing.EventingV1alpha1().Brokers(broker.Namespace) res, err := brokers.Create(broker) @@ -186,7 +186,7 @@ func WaitForBrokerReady(clients *test.Clients, broker *v1alpha1.Broker) error { if err := test.WaitForBrokerState(brokers, broker.Name, test.IsBrokerReady, "BrokerIsReady"); err != nil { return err } - // Update the given object so they'll reflect the ready state + // Update the given object so they'll reflect the ready state. updatedBroker, err := brokers.Get(broker.Name, metav1.GetOptions{}) if err != nil { return err @@ -195,7 +195,7 @@ func WaitForBrokerReady(clients *test.Clients, broker *v1alpha1.Broker) error { return nil } -// CreateTrigger will create a Trigger +// CreateTrigger will create a Trigger. func CreateTrigger(clients *test.Clients, trigger *v1alpha1.Trigger, logger *logging.BaseLogger, cleaner *test.Cleaner) error { triggers := clients.Eventing.EventingV1alpha1().Triggers(trigger.Namespace) res, err := triggers.Create(trigger) @@ -216,7 +216,7 @@ func WithTriggerReady(clients *test.Clients, trigger *v1alpha1.Trigger, logger * if err := test.WaitForTriggerState(triggers, trigger.Name, test.IsTriggerReady, "TriggerIsReady"); err != nil { return err } - // Update the given object so they'll reflect the ready state + // Update the given object so they'll reflect the ready state. updatedTrigger, err := triggers.Get(trigger.Name, metav1.GetOptions{}) if err != nil { return err @@ -321,7 +321,7 @@ func PodLogs(clients *test.Clients, podName string, containerName string, namesp }).Do() raw, err := result.Raw() if err == nil { - logger.Debugf("%s logs request result: %#v", podName, string(raw)) + logger.Infof("%s logs request result: %#v", podName, string(raw)) } else { logger.Infof("%s logs request result: %#v", podName, err) } @@ -352,6 +352,22 @@ func WaitForLogContents(clients *test.Clients, logger *logging.BaseLogger, podNa }) } +// FindAnyLogContents attempts to find logs for given Pod/Container that has 'any' of the given contents. +// It returns an error if it couldn't retrieve the logs. In case 'any' of the contents are there, it returns true. +func FindAnyLogContents(clients *test.Clients, logger *logging.BaseLogger, podName string, containerName string, namespace string, contents []string) (bool, error) { + logs, err := PodLogs(clients, podName, containerName, namespace, logger) + if err != nil { + return false, err + } + for _, content := range contents { + if strings.Contains(string(logs), content) { + logger.Infof("Found content %q for %s/%s.", content, podName, containerName) + return true, nil + } + } + return false, nil +} + // WaitForLogContent waits until logs for given Pod/Container include the given content. // If the content is not present within timeout it returns error. func WaitForLogContent(clients *test.Clients, logger *logging.BaseLogger, podName string, containerName string, namespace string, content string) error { From 7f24f14770e27c3d90e5a179971fde1f7f2a996a Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Fri, 22 Feb 2019 20:14:11 -0800 Subject: [PATCH 094/221] Adding some more logs and trailing dots. --- test/builders.go | 1 + test/e2e/broker_trigger_test.go | 6 +++--- test/e2e/e2e.go | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/test/builders.go b/test/builders.go index 3de022ad65e..c73822bad4d 100644 --- a/test/builders.go +++ b/test/builders.go @@ -19,6 +19,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) +// Builder for trigger objects. type TriggerBuilder struct { *eventingv1alpha1.Trigger } diff --git a/test/e2e/broker_trigger_test.go b/test/e2e/broker_trigger_test.go index aa7b674d104..b478c673381 100644 --- a/test/e2e/broker_trigger_test.go +++ b/test/e2e/broker_trigger_test.go @@ -232,7 +232,7 @@ func TestDefaultBrokerWithManyTriggers(t *testing.T) { t.Fatalf("Event(s) not found in logs of subscriber pod %q: %v", subscriberPodName, err) } // At this point all the events should have been received in the pod. - // We check whether we find them unexpected events. If so, then we fail. + // We check whether we find unexpected events. If so, then we fail. found, err := FindAnyLogContents(clients, logger, subscriberPodName, subscriberPod.Spec.Containers[0].Name, ns, unexpectedEvents[subscriberPodName]) if err != nil { t.Fatalf("Failed querying to find log contents in pod %q: %v", subscriberPodName, err) @@ -243,9 +243,9 @@ func TestDefaultBrokerWithManyTriggers(t *testing.T) { } } -// Helper function to create names for different objects (e.g., triggers, services, etc.) +// Helper function to create names for different objects (e.g., triggers, services, etc.). func name(obj, eventType, eventSource string) string { - // pod names need to be lowercase. We might have an eventType as Any, that is why we lowercase them. + // Pod names need to be lowercase. We might have an eventType as Any, that is why we lowercase them. return strings.ToLower(fmt.Sprintf("%s-%s-%s", obj, eventType, eventSource)) } diff --git a/test/e2e/e2e.go b/test/e2e/e2e.go index f81d7452812..98079dfe015 100644 --- a/test/e2e/e2e.go +++ b/test/e2e/e2e.go @@ -382,7 +382,7 @@ func WaitForAllPodsRunning(clients *test.Clients, logger *logging.BaseLogger, na return nil } -// WaitForAllTriggersReady will wait until all triggers in the given namespace are ready +// WaitForAllTriggersReady will wait until all triggers in the given namespace are ready. func WaitForAllTriggersReady(clients *test.Clients, logger *logging.BaseLogger, namespace string) error { triggers := clients.Eventing.EventingV1alpha1().Triggers(namespace) if err := test.WaitForTriggersListState(triggers, test.TriggersReady, "TriggerIsReady"); err != nil { @@ -391,7 +391,7 @@ func WaitForAllTriggersReady(clients *test.Clients, logger *logging.BaseLogger, return nil } -// AnnotateNamespace annotates the test namespace with the annotations map +// AnnotateNamespace annotates the test namespace with the annotations map. func AnnotateNamespace(clients *test.Clients, logger *logging.BaseLogger, annotations map[string]string) error { ns := pkgTest.Flags.Namespace nsSpec, err := clients.Kube.Kube.CoreV1().Namespaces().Get(ns, metav1.GetOptions{}) From 9debaf250b6c488b6ed49e1fd5b38ebeeb96bb79 Mon Sep 17 00:00:00 2001 From: Adam Harwayne Date: Mon, 25 Feb 2019 11:42:32 -0800 Subject: [PATCH 095/221] Switch import order. --- cmd/controller/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/controller/main.go b/cmd/controller/main.go index 2619ec145aa..382e79d38a7 100644 --- a/cmd/controller/main.go +++ b/cmd/controller/main.go @@ -24,8 +24,8 @@ import ( "os" "time" - "github.com/knative/eventing/pkg/reconciler/v1alpha1/namespace" "github.com/knative/eventing/pkg/reconciler/v1alpha1/broker" + "github.com/knative/eventing/pkg/reconciler/v1alpha1/namespace" "github.com/knative/eventing/pkg/reconciler/v1alpha1/subscription" "github.com/knative/eventing/pkg/reconciler/v1alpha1/trigger" "k8s.io/apimachinery/pkg/runtime" From a83ca8223dca0a36b42ba9bb4190b9f5d92a6c7b Mon Sep 17 00:00:00 2001 From: nachocano Date: Mon, 25 Feb 2019 12:06:45 -0800 Subject: [PATCH 096/221] Updating comments. --- cmd/broker/filter/main.go | 6 +- cmd/broker/ingress/main.go | 10 +-- pkg/broker/receiver.go | 6 +- pkg/reconciler/v1alpha1/broker/broker.go | 26 +++++--- .../v1alpha1/namespace/namespace.go | 62 ++++++++++++------- pkg/reconciler/v1alpha1/trigger/trigger.go | 24 +++++-- 6 files changed, 87 insertions(+), 47 deletions(-) diff --git a/cmd/broker/filter/main.go b/cmd/broker/filter/main.go index 0c39dec0550..9e3b2d5fdb5 100644 --- a/cmd/broker/filter/main.go +++ b/cmd/broker/filter/main.go @@ -47,10 +47,8 @@ func main() { // Add custom types to this array to get them into the manager's scheme. eventingv1alpha1.AddToScheme(mgr.GetScheme()) - // We are running both the receiver (takes messages in from the cluster and writes them to - // PubSub) and the dispatcher (takes messages in PubSub and sends them in cluster) in this - // binary. - + // We are running both the receiver (takes messages in from the cluster) and the dispatcher (send the messages + // to the triggers' subscribers) in this binary. _, runnable := broker.New(logger, mgr.GetClient()) err = mgr.Add(runnable) if err != nil { diff --git a/cmd/broker/ingress/main.go b/cmd/broker/ingress/main.go index 1be24c382bb..3db11df68a9 100644 --- a/cmd/broker/ingress/main.go +++ b/cmd/broker/ingress/main.go @@ -74,7 +74,7 @@ func main() { // Start both the manager (which notices ConfigMap changes) and the HTTP server. var g errgroup.Group g.Go(func() error { - // set up signals so we handle the first shutdown signal gracefully + // Set up signals so we handle the first shutdown signal gracefully. stopCh := signals.SetupSignalHandler() // Start blocks forever, so run it in a goroutine. return mgr.Start(stopCh) @@ -99,7 +99,7 @@ func getRequiredEnv(envKey string) string { return val } -// http.Handler that takes a single request in and fans it out to N other servers. +// http.Handler that takes a single request in and sends it out to a single destination. type Handler struct { receiver *provisioners.MessageReceiver dispatcher *provisioners.MessageDispatcher @@ -108,7 +108,7 @@ type Handler struct { logger *zap.Logger } -// NewHandler creates a new fanout.Handler. +// NewHandler creates a new ingress.Handler. func NewHandler(logger *zap.Logger, destination string) *Handler { handler := &Handler{ logger: logger, @@ -133,8 +133,8 @@ func (f *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { f.receiver.HandleRequest(w, r) } -// dispatch takes the request, fans it out to each subscription in f.config. If all the fanned out -// requests return successfully, then return nil. Else, return an error. +// dispatch takes the request, and sends it out the f.destination. If the dispatched +// request returns successfully, then return nil. Else, return an error. func (f *Handler) dispatch(msg *provisioners.Message) error { err := f.dispatcher.DispatchMessage(msg, f.destination, "", provisioners.DispatchDefaults{}) if err != nil { diff --git a/pkg/broker/receiver.go b/pkg/broker/receiver.go index 9dd264337ee..1f294d7c942 100644 --- a/pkg/broker/receiver.go +++ b/pkg/broker/receiver.go @@ -28,7 +28,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/manager" ) -// Receiver parses Cloud Events and sends them to the channel. +// Receiver parses Cloud Events and sends them to the subscriber(s). type Receiver struct { logger *zap.Logger client client.Client @@ -51,7 +51,7 @@ func (r *Receiver) newMessageReceiver() *provisioners.MessageReceiver { return provisioners.NewMessageReceiver(r.sendEvent, r.logger.Sugar()) } -// sendEvent sends a message to the Channel. +// sendEvent sends an event to a subscriber if the trigger filter passes. func (r *Receiver) sendEvent(channel provisioners.ChannelReference, message *provisioners.Message) error { r.logger.Debug("received message") ctx := context.Background() @@ -97,6 +97,8 @@ func (r *Receiver) getTrigger(ctx context.Context, ref provisioners.ChannelRefer return t, err } +// shouldSendMessage determines whether message 'm' should be sent based on the triggerSpec 'ts'. +// Currently it supports exact matching on type and/or source of events. func (r *Receiver) shouldSendMessage(ts *eventingv1alpha1.TriggerSpec, m *provisioners.Message) bool { if ts.Filter == nil || ts.Filter.SourceAndType == nil { r.logger.Error("No filter specified") diff --git a/pkg/reconciler/v1alpha1/broker/broker.go b/pkg/reconciler/v1alpha1/broker/broker.go index 1e4c52b2735..f970acd9dc4 100644 --- a/pkg/reconciler/v1alpha1/broker/broker.go +++ b/pkg/reconciler/v1alpha1/broker/broker.go @@ -19,9 +19,10 @@ package broker import ( "context" "fmt" - "k8s.io/apimachinery/pkg/runtime" "time" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/dynamic" "k8s.io/client-go/rest" "k8s.io/client-go/tools/record" @@ -60,7 +61,7 @@ const ( // itself when creating events. controllerAgentName = "broker-controller" - // Name of the corev1.Events emitted from the reconciliation process + // Name of the corev1.Events emitted from the reconciliation process. brokerReconciled = "BrokerReconciled" brokerUpdateStatusFailed = "BrokerUpdateStatusFailed" ) @@ -79,7 +80,7 @@ type reconciler struct { filterServiceAccountName string } -// Verify the struct implements reconcile.Reconciler +// Verify the struct implements reconcile.Reconciler. var _ reconcile.Reconciler = &reconciler{} // ProvideController returns a function that returns a Broker controller. @@ -155,7 +156,7 @@ func (r *reconciler) Reconcile(request reconcile.Request) (reconcile.Result, err result, reconcileErr := r.reconcile(ctx, broker) if reconcileErr != nil { logging.FromContext(ctx).Error("Error reconciling Broker", zap.Error(reconcileErr)) - } else if result.Requeue || result.RequeueAfter > 0 { + } else if result.Requeue || result.RequeueAfter > 0 { logging.FromContext(ctx).Debug("Broker reconcile requeuing") } else { logging.FromContext(ctx).Debug("Broker reconciled") @@ -178,7 +179,7 @@ func (r *reconciler) reconcile(ctx context.Context, b *v1alpha1.Broker) (reconci // 1. Channel is created for all events. // 2. Filter Deployment. // 3. Ingress Deployment. - // 4. K8s Service that points at the Deployment. + // 4. K8s Services that point at the Deployments. if b.DeletionTimestamp != nil { // Everything is cleaned up by the garbage collector. @@ -217,7 +218,7 @@ func (r *reconciler) reconcile(ctx context.Context, b *v1alpha1.Broker) (reconci svc, err := r.reconcileIngressService(ctx, b) if err != nil { - logging.FromContext(ctx).Error("Problem reconciling ingress Service", zap.Error(err)) + logging.FromContext(ctx).Error("Problem reconciling ingress service", zap.Error(err)) return reconcile.Result{}, err } b.Status.MarkIngressReady() @@ -226,7 +227,7 @@ func (r *reconciler) reconcile(ctx context.Context, b *v1alpha1.Broker) (reconci return reconcile.Result{}, nil } -// updateStatus may in fact update the broker's finalizers in addition to the status +// updateStatus may in fact update the broker's finalizers in addition to the status. func (r *reconciler) updateStatus(broker *v1alpha1.Broker) (*v1alpha1.Broker, error) { objectKey := client.ObjectKey{Namespace: broker.Namespace, Name: broker.Name} latestBroker := &v1alpha1.Broker{} @@ -250,7 +251,7 @@ func (r *reconciler) updateStatus(broker *v1alpha1.Broker) (*v1alpha1.Broker, er } if brokerChanged { - // Refetch + // Re-fetch. latestBroker = &v1alpha1.Broker{} if err := r.client.Get(context.TODO(), objectKey, latestBroker); err != nil { return nil, err @@ -265,6 +266,7 @@ func (r *reconciler) updateStatus(broker *v1alpha1.Broker) (*v1alpha1.Broker, er return latestBroker, nil } +// reconcileFilterDeployment reconciles Broker's 'b' filter deployment. func (r *reconciler) reconcileFilterDeployment(ctx context.Context, b *v1alpha1.Broker) (*v1.Deployment, error) { expected := resources.MakeFilterDeployment(&resources.FilterArgs{ Broker: b, @@ -274,11 +276,13 @@ func (r *reconciler) reconcileFilterDeployment(ctx context.Context, b *v1alpha1. return r.reconcileDeployment(ctx, expected) } +// reconcileFilterService reconciles Broker's 'b' filter service. func (r *reconciler) reconcileFilterService(ctx context.Context, b *v1alpha1.Broker) (*corev1.Service, error) { expected := resources.MakeFilterService(b) return r.reconcileService(ctx, expected) } +// reconcileChannel reconciles Broker's 'b' underlying channel. func (r *reconciler) reconcileChannel(ctx context.Context, b *v1alpha1.Broker) (*v1alpha1.Channel, error) { c, err := r.getChannel(ctx, b) // If the resource doesn't exist, we'll create it @@ -307,6 +311,7 @@ func (r *reconciler) reconcileChannel(ctx context.Context, b *v1alpha1.Broker) ( return c, nil } +// getChannel returns the Channel object for Broker 'b' if exists, otherwise it returns an error. func (r *reconciler) getChannel(ctx context.Context, b *v1alpha1.Broker) (*v1alpha1.Channel, error) { list := &v1alpha1.ChannelList{} opts := &runtimeclient.ListOptions{ @@ -335,6 +340,7 @@ func (r *reconciler) getChannel(ctx context.Context, b *v1alpha1.Broker) (*v1alp return nil, k8serrors.NewNotFound(schema.GroupResource{}, "") } +// newChannel creates a new placeholder Channel object for Broker 'b'. func newChannel(b *v1alpha1.Broker) *v1alpha1.Channel { var spec v1alpha1.ChannelSpec if b.Spec.ChannelTemplate != nil { @@ -365,6 +371,7 @@ func ChannelLabels(b *v1alpha1.Broker) map[string]string { } } +// reconcileDeployment reconciles the K8s Deployment 'd'. func (r *reconciler) reconcileDeployment(ctx context.Context, d *v1.Deployment) (*v1.Deployment, error) { name := types.NamespacedName{ Namespace: d.Namespace, @@ -392,6 +399,7 @@ func (r *reconciler) reconcileDeployment(ctx context.Context, d *v1.Deployment) return current, nil } +// reconcileService reconciles the K8s Service 'svc'. func (r *reconciler) reconcileService(ctx context.Context, svc *corev1.Service) (*corev1.Service, error) { name := types.NamespacedName{ Namespace: svc.Namespace, @@ -422,6 +430,7 @@ func (r *reconciler) reconcileService(ctx context.Context, svc *corev1.Service) return current, nil } +// reconcileIngressDeployment reconciles the Ingress Deployment. func (r *reconciler) reconcileIngressDeployment(ctx context.Context, b *v1alpha1.Broker, c *v1alpha1.Channel) (*v1.Deployment, error) { expected := resources.MakeIngress(&resources.IngressArgs{ Broker: b, @@ -432,6 +441,7 @@ func (r *reconciler) reconcileIngressDeployment(ctx context.Context, b *v1alpha1 return r.reconcileDeployment(ctx, expected) } +// reconcileIngressService reconciles the Ingress Service. func (r *reconciler) reconcileIngressService(ctx context.Context, b *v1alpha1.Broker) (*corev1.Service, error) { expected := resources.MakeIngressService(b) return r.reconcileService(ctx, expected) diff --git a/pkg/reconciler/v1alpha1/namespace/namespace.go b/pkg/reconciler/v1alpha1/namespace/namespace.go index 483d659604d..58b1bcd045e 100644 --- a/pkg/reconciler/v1alpha1/namespace/namespace.go +++ b/pkg/reconciler/v1alpha1/namespace/namespace.go @@ -19,11 +19,12 @@ package namespace import ( "context" "fmt" + "github.com/knative/eventing/contrib/gcppubsub/pkg/util/logging" "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" "go.uber.org/zap" - "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1" + v1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" "k8s.io/apimachinery/pkg/api/errors" k8serrors "k8s.io/apimachinery/pkg/api/errors" @@ -46,16 +47,17 @@ const ( // itself when creating events. controllerAgentName = "knative-eventing-namespace-controller" - defaultBroker = "default" - brokerFilterSA = "eventing-broker-filter" - brokerFilterRB = "eventing-broker-filter" + defaultBroker = "default" + brokerFilterSA = "eventing-broker-filter" + brokerFilterRB = "eventing-broker-filter" brokerFilterClusterRole = "eventing-broker-filter" + // Annotation to enable knative-eventing in a namespace. knativeEventingAnnotation = "eventing.knative.dev/inject" // Name of the corev1.Events emitted from the reconciliation process. - brokerCreated = "BrokerCreated" - serviceAccountCreated = "BrokerFilterServiceAccountCreated" + brokerCreated = "BrokerCreated" + serviceAccountCreated = "BrokerFilterServiceAccountCreated" serviceAccountRBACCreated = "BrokerFilterServiceAccountRBACCreated" ) @@ -71,10 +73,10 @@ type reconciler struct { // Verify the struct implements reconcile.Reconciler var _ reconcile.Reconciler = &reconciler{} -// ProvideController returns a function that returns a Broker controller. +// ProvideController returns a function that returns a Namespace controller. func ProvideController(logger *zap.Logger) func(manager.Manager) (controller.Controller, error) { return func(mgr manager.Manager) (controller.Controller, error) { - // Setup a new controller to Reconcile Brokers. + // Setup a new controller to Reconcile Namespaces. r := &reconciler{ recorder: mgr.GetRecorder(controllerAgentName), logger: logger, @@ -92,8 +94,8 @@ func ProvideController(logger *zap.Logger) func(manager.Manager) (controller.Con } // Watch all the resources that this reconciler reconciles. - for _, t := range []runtime.Object{ &corev1.ServiceAccount{}, &rbacv1.RoleBinding{}, &v1alpha1.Broker{} } { - err = c.Watch(&source.Kind{Type: t}, &handler.EnqueueRequestsFromMapFunc{ToRequests: &namespaceMapper{}}); + for _, t := range []runtime.Object{&corev1.ServiceAccount{}, &rbacv1.RoleBinding{}, &v1alpha1.Broker{}} { + err = c.Watch(&source.Kind{Type: t}, &handler.EnqueueRequestsFromMapFunc{ToRequests: &namespaceMapper{}}) if err != nil { return nil, err } @@ -131,7 +133,7 @@ func (r *reconciler) InjectConfig(c *rest.Config) error { } // Reconcile compares the actual state with the desired, and attempts to -// converge the two. It then updates the Status block of the Trigger resource +// converge the two. It then updates the Status block of the Namespace resource // with the current status of the resource. func (r *reconciler) Reconcile(request reconcile.Request) (reconcile.Result, error) { ctx := context.TODO() @@ -155,7 +157,7 @@ func (r *reconciler) Reconcile(request reconcile.Request) (reconcile.Result, err return reconcile.Result{}, nil } - // Reconcile this copy of the Trigger and then write back any status updates regardless of + // Reconcile this copy of the Namespace and then write back any status updates regardless of // whether the reconcile error out. reconcileErr := r.reconcile(ctx, ns) if reconcileErr != nil { @@ -185,13 +187,14 @@ func (r *reconciler) reconcile(ctx context.Context, ns *corev1.Namespace) error } _, err = r.reconcileBroker(ctx, ns) if err != nil { - logging.FromContext(ctx).Error("Unable to reconcile broker for the namespace", zap.Error(err)) + logging.FromContext(ctx).Error("Unable to reconcile Broker for the namespace", zap.Error(err)) return err } return nil } +// reconcileBrokerFilterServiceAccount reconciles the Broker's filter service account for Namespace 'ns'. func (r *reconciler) reconcileBrokerFilterServiceAccount(ctx context.Context, ns *corev1.Namespace) (*corev1.ServiceAccount, error) { current, err := r.getBrokerFilterServiceAccount(ctx, ns) @@ -214,6 +217,8 @@ func (r *reconciler) reconcileBrokerFilterServiceAccount(ctx context.Context, ns return current, nil } +// getBrokerFilterServiceAccount returns the Broker's filter service account for Namespace 'ns' if exists, +// otherwise it returns an error. func (r *reconciler) getBrokerFilterServiceAccount(ctx context.Context, ns *corev1.Namespace) (*corev1.ServiceAccount, error) { sa := &corev1.ServiceAccount{} name := types.NamespacedName{ @@ -224,12 +229,13 @@ func (r *reconciler) getBrokerFilterServiceAccount(ctx context.Context, ns *core return sa, err } +// newBrokerFilterServiceAccount creates a ServiceAccount object for the Namespace 'ns'. func newBrokerFilterServiceAccount(ns *corev1.Namespace) *corev1.ServiceAccount { return &corev1.ServiceAccount{ ObjectMeta: metav1.ObjectMeta{ Namespace: ns.Name, - Name: brokerFilterSA, - Labels: injectedLabels(), + Name: brokerFilterSA, + Labels: injectedLabels(), }, } } @@ -240,6 +246,7 @@ func injectedLabels() map[string]string { } } +// reconcileBrokerFilterRBAC reconciles the Broker's filter service account RBAC for the Namespace 'ns'. func (r *reconciler) reconcileBrokerFilterRBAC(ctx context.Context, ns *corev1.Namespace, sa *corev1.ServiceAccount) (*rbacv1.RoleBinding, error) { current, err := r.getBrokerFilterRBAC(ctx, ns) @@ -262,6 +269,8 @@ func (r *reconciler) reconcileBrokerFilterRBAC(ctx context.Context, ns *corev1.N return current, nil } +// getBrokerFilterRBAC returns the Broker's filter role binding for Namespace 'ns' if exists, +// otherwise it returns an error. func (r *reconciler) getBrokerFilterRBAC(ctx context.Context, ns *corev1.Namespace) (*rbacv1.RoleBinding, error) { rb := &rbacv1.RoleBinding{} name := types.NamespacedName{ @@ -272,28 +281,31 @@ func (r *reconciler) getBrokerFilterRBAC(ctx context.Context, ns *corev1.Namespa return rb, err } +// newBrokerFilterRBAC creates a RpleBinding object for the Broker's filter service account 'sa' in the Namespace 'ns'. func newBrokerFilterRBAC(ns *corev1.Namespace, sa *corev1.ServiceAccount) *rbacv1.RoleBinding { return &rbacv1.RoleBinding{ ObjectMeta: metav1.ObjectMeta{ Namespace: ns.Name, - Name: brokerFilterRB, - Labels: injectedLabels(), + Name: brokerFilterRB, + Labels: injectedLabels(), }, - RoleRef:rbacv1.RoleRef{ - APIGroup:"rbac.authorization.k8s.io", - Kind: "ClusterRole", - Name: brokerFilterClusterRole, + RoleRef: rbacv1.RoleRef{ + APIGroup: "rbac.authorization.k8s.io", + Kind: "ClusterRole", + Name: brokerFilterClusterRole, }, - Subjects:[]rbacv1.Subject{ + Subjects: []rbacv1.Subject{ { - Kind: "ServiceAccount", + Kind: "ServiceAccount", Namespace: ns.Name, - Name: sa.Name, + Name: sa.Name, }, }, } } +// getBroker returns the default broker for Namespace 'ns' if exists, +// otherwise it returns an error. func (r *reconciler) getBroker(ctx context.Context, ns *corev1.Namespace) (*v1alpha1.Broker, error) { b := &v1alpha1.Broker{} name := types.NamespacedName{ @@ -304,6 +316,7 @@ func (r *reconciler) getBroker(ctx context.Context, ns *corev1.Namespace) (*v1al return b, err } +// reconcileBroker reconciles the default Broker for the Namespace 'ns'. func (r *reconciler) reconcileBroker(ctx context.Context, ns *corev1.Namespace) (*v1alpha1.Broker, error) { current, err := r.getBroker(ctx, ns) @@ -323,6 +336,7 @@ func (r *reconciler) reconcileBroker(ctx context.Context, ns *corev1.Namespace) return current, nil } +// newBroker creates a placeholder default Broker object for Namespace 'ns'. func newBroker(ns *corev1.Namespace) *v1alpha1.Broker { return &v1alpha1.Broker{ ObjectMeta: metav1.ObjectMeta{ diff --git a/pkg/reconciler/v1alpha1/trigger/trigger.go b/pkg/reconciler/v1alpha1/trigger/trigger.go index 42404fed7fa..b9e6e8b2341 100644 --- a/pkg/reconciler/v1alpha1/trigger/trigger.go +++ b/pkg/reconciler/v1alpha1/trigger/trigger.go @@ -62,7 +62,7 @@ const ( finalizerName = controllerAgentName - // Name of the corev1.Events emitted from the reconciliation process + // Name of the corev1.Events emitted from the reconciliation process. triggerReconciled = "TriggerReconciled" triggerReconcileFailed = "TriggerReconcileFailed" triggerUpdateStatusFailed = "TriggerUpdateStatusFailed" @@ -87,7 +87,7 @@ type reconciler struct { logger *zap.Logger } -// Verify the struct implements reconcile.Reconciler +// Verify the struct implements reconcile.Reconciler. var _ reconcile.Reconciler = &reconciler{} // ProvideController returns a function that returns a Trigger controller. @@ -369,6 +369,8 @@ func (r *reconciler) updateStatus(trigger *v1alpha1.Trigger) (*v1alpha1.Trigger, return latestTrigger, nil } +// getBroker returns the Broker for Trigger 't' if exists, +// otherwise it returns an error. func (r *reconciler) getBroker(ctx context.Context, t *v1alpha1.Trigger) (*v1alpha1.Broker, error) { b := &v1alpha1.Broker{} name := types.NamespacedName{ @@ -379,6 +381,8 @@ func (r *reconciler) getBroker(ctx context.Context, t *v1alpha1.Trigger) (*v1alp return b, err } +// getBrokerChannel returns the Broker's channel if exists, +// otherwise it returns an error. func (r *reconciler) getBrokerChannel(ctx context.Context, b *v1alpha1.Broker) (*v1alpha1.Channel, error) { list := &v1alpha1.ChannelList{} opts := &runtimeclient.ListOptions{ @@ -407,6 +411,8 @@ func (r *reconciler) getBrokerChannel(ctx context.Context, b *v1alpha1.Broker) ( return nil, k8serrors.NewNotFound(schema.GroupResource{}, "") } +// getK8sService returns the K8s service for trigger 't' if exists, +// otherwise it returns an error. func (r *reconciler) getK8sService(ctx context.Context, t *v1alpha1.Trigger) (*corev1.Service, error) { list := &corev1.ServiceList{} opts := &runtimeclient.ListOptions{ @@ -435,6 +441,7 @@ func (r *reconciler) getK8sService(ctx context.Context, t *v1alpha1.Trigger) (*c return nil, k8serrors.NewNotFound(schema.GroupResource{}, "") } +// reconcileK8sService reconciles the K8s service for trigger 't'. func (r *reconciler) reconcileK8sService(ctx context.Context, t *v1alpha1.Trigger) (*corev1.Service, error) { current, err := r.getK8sService(ctx, t) @@ -464,6 +471,7 @@ func (r *reconciler) reconcileK8sService(ctx context.Context, t *v1alpha1.Trigge return current, nil } +// newK8sService returns a K8s placeholder service for trigger 't'. func newK8sService(t *v1alpha1.Trigger) *corev1.Service { return &corev1.Service{ ObjectMeta: metav1.ObjectMeta{ @@ -495,6 +503,8 @@ func k8sServiceLabels(t *v1alpha1.Trigger) map[string]string { } } +// getVirtualService returns the virtual service for trigger 't' if exists, +// otherwise it returns an error. func (r *reconciler) getVirtualService(ctx context.Context, t *v1alpha1.Trigger) (*istiov1alpha3.VirtualService, error) { list := &istiov1alpha3.VirtualServiceList{} opts := &runtimeclient.ListOptions{ @@ -523,6 +533,7 @@ func (r *reconciler) getVirtualService(ctx context.Context, t *v1alpha1.Trigger) return nil, k8serrors.NewNotFound(schema.GroupResource{}, "") } +// reconcileVirtualService reconciles the virtual service for trigger 't' and service 'svc'. func (r *reconciler) reconcileVirtualService(ctx context.Context, t *v1alpha1.Trigger, svc *corev1.Service) (*istiov1alpha3.VirtualService, error) { virtualService, err := r.getVirtualService(ctx, t) @@ -549,6 +560,7 @@ func (r *reconciler) reconcileVirtualService(ctx context.Context, t *v1alpha1.Tr return virtualService, nil } +// newVirtualService returns a placeholder virtual service object for trigger 't' and service 'svc'. func newVirtualService(t *v1alpha1.Trigger, svc *corev1.Service) *istiov1alpha3.VirtualService { // TODO Make this work with endings other than cluster.local destinationHost := fmt.Sprintf("%s-broker-filter.%s.svc.cluster.local", t.Spec.Broker, t.Namespace) @@ -593,10 +605,11 @@ func virtualServiceLabels(t *v1alpha1.Trigger) map[string]string { } } +// subscribeToBrokerChannel subscribes service 'svc' to Broker's channel 'c'. func (r *reconciler) subscribeToBrokerChannel(ctx context.Context, t *v1alpha1.Trigger, c *v1alpha1.Channel, svc *corev1.Service) (*v1alpha1.Subscription, error) { expected := makeSubscription(t, c, svc) - sub, err := r.getSubscription(ctx, t, c) + sub, err := r.getSubscription(ctx, t) // If the resource doesn't exist, we'll create it if k8serrors.IsNotFound(err) { sub = expected @@ -631,7 +644,9 @@ func (r *reconciler) subscribeToBrokerChannel(ctx context.Context, t *v1alpha1.T return sub, nil } -func (r *reconciler) getSubscription(ctx context.Context, t *v1alpha1.Trigger, c *v1alpha1.Channel) (*v1alpha1.Subscription, error) { +// getSubscription returns the subscription of trigger 't' if exists, +// otherwise it returns an error. +func (r *reconciler) getSubscription(ctx context.Context, t *v1alpha1.Trigger) (*v1alpha1.Subscription, error) { list := &v1alpha1.SubscriptionList{} opts := &runtimeclient.ListOptions{ Namespace: t.Namespace, @@ -659,6 +674,7 @@ func (r *reconciler) getSubscription(ctx context.Context, t *v1alpha1.Trigger, c return nil, k8serrors.NewNotFound(schema.GroupResource{}, "") } +// makeSubscription returns a placeholder subscription for trigger 't', channel 'c', and service 'svc'. func makeSubscription(t *v1alpha1.Trigger, c *v1alpha1.Channel, svc *corev1.Service) *v1alpha1.Subscription { return &v1alpha1.Subscription{ ObjectMeta: metav1.ObjectMeta{ From fda6550eb16ceb2ef305c6afcc9059a0a3f0b40c Mon Sep 17 00:00:00 2001 From: nachocano Date: Mon, 25 Feb 2019 12:08:48 -0800 Subject: [PATCH 097/221] Updating comments. --- pkg/broker/receiver.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/broker/receiver.go b/pkg/broker/receiver.go index 1f294d7c942..8034b495799 100644 --- a/pkg/broker/receiver.go +++ b/pkg/broker/receiver.go @@ -28,7 +28,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/manager" ) -// Receiver parses Cloud Events and sends them to the subscriber(s). +// Receiver parses Cloud Events and sends them to a subscriber. type Receiver struct { logger *zap.Logger client client.Client From 2aae7eba80de2e578596525831896beb55931efd Mon Sep 17 00:00:00 2001 From: Adam Harwayne Date: Mon, 25 Feb 2019 12:16:43 -0800 Subject: [PATCH 098/221] Replace the bad errgroup usage with the runnableServer. --- cmd/broker/ingress/main.go | 41 +++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/cmd/broker/ingress/main.go b/cmd/broker/ingress/main.go index 1be24c382bb..2c116bdd18a 100644 --- a/cmd/broker/ingress/main.go +++ b/cmd/broker/ingress/main.go @@ -25,8 +25,6 @@ import ( "os" "time" - "golang.org/x/sync/errgroup" - eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" "github.com/knative/eventing/pkg/provisioners" "github.com/knative/pkg/signals" @@ -71,24 +69,27 @@ func main() { WriteTimeout: writeTimeout, } - // Start both the manager (which notices ConfigMap changes) and the HTTP server. - var g errgroup.Group - g.Go(func() error { - // set up signals so we handle the first shutdown signal gracefully - stopCh := signals.SetupSignalHandler() - // Start blocks forever, so run it in a goroutine. - return mgr.Start(stopCh) + err = mgr.Add(&runnableServer{ + logger: logger, + s: s, }) - logger.Info("Ingress Listening...", zap.String("Address", s.Addr)) - g.Go(s.ListenAndServe) - err = g.Wait() if err != nil { - logger.Error("HTTP server failed.", zap.Error(err)) + logger.Fatal("Unable to add ListenAndServe", zap.Error(err)) + } + + // Set up signals so we handle the first shutdown signal gracefully. + stopCh := signals.SetupSignalHandler() + // Start blocks forever. + if err = mgr.Start(stopCh); err != nil { + logger.Error("manager.Start() returned an error", zap.Error(err)) } + logger.Info("Exiting...") ctx, cancel := context.WithTimeout(context.Background(), writeTimeout) defer cancel() - s.Shutdown(ctx) + if err = s.Shutdown(ctx); err != nil { + logger.Error("Shutdown returned an error", zap.Error(err)) + } } func getRequiredEnv(envKey string) string { @@ -142,3 +143,15 @@ func (f *Handler) dispatch(msg *provisioners.Message) error { } return err } + +// runnableServer is a small wrapper around http.Server so that it matches the manager.Runnable +// interface. +type runnableServer struct { + logger *zap.Logger + s *http.Server +} + +func (r *runnableServer) Start(<-chan struct{}) error { + r.logger.Info("Ingress Listening...", zap.String("Address", r.s.Addr)) + return r.s.ListenAndServe() +} From 5f201fa4afc44652856111e27359860f3bbd7e19 Mon Sep 17 00:00:00 2001 From: Adam Harwayne Date: Mon, 25 Feb 2019 12:36:51 -0800 Subject: [PATCH 099/221] Namespace scoped the Broker Filter's client. --- cmd/broker/filter/main.go | 22 ++++++++++- pkg/broker/receiver.go | 4 -- .../v1alpha1/broker/resources/filter.go | 10 +++-- .../v1alpha1/namespace/namespace.go | 39 ++++++++++--------- 4 files changed, 47 insertions(+), 28 deletions(-) diff --git a/cmd/broker/filter/main.go b/cmd/broker/filter/main.go index 0c39dec0550..d38919b1766 100644 --- a/cmd/broker/filter/main.go +++ b/cmd/broker/filter/main.go @@ -18,6 +18,8 @@ package main import ( "flag" + "log" + "os" eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" "github.com/knative/eventing/pkg/broker" @@ -29,6 +31,10 @@ import ( "sigs.k8s.io/controller-runtime/pkg/manager" ) +const ( + NAMESPACE = "NAMESPACE" +) + func main() { logConfig := provisioners.NewLoggingConfig() logConfig.LoggingLevel["provisioner"] = zapcore.DebugLevel @@ -39,13 +45,17 @@ func main() { logger.Info("Starting...") - mgr, err := manager.New(config.GetConfigOrDie(), manager.Options{}) + mgr, err := manager.New(config.GetConfigOrDie(), manager.Options{ + Namespace: getRequiredEnv(NAMESPACE), + }) if err != nil { logger.Fatal("Error starting up.", zap.Error(err)) } // Add custom types to this array to get them into the manager's scheme. - eventingv1alpha1.AddToScheme(mgr.GetScheme()) + if err = eventingv1alpha1.AddToScheme(mgr.GetScheme()); err != nil { + logger.Fatal("Unable to add eventingv1alpha1 scheme", zap.Error(err)) + } // We are running both the receiver (takes messages in from the cluster and writes them to // PubSub) and the dispatcher (takes messages in PubSub and sends them in cluster) in this @@ -67,3 +77,11 @@ func main() { logger.Fatal("Manager.Start() returned an error", zap.Error(err)) } } + +func getRequiredEnv(envKey string) string { + val, defined := os.LookupEnv(envKey) + if !defined { + log.Fatalf("required environment variable not defined '%s'", envKey) + } + return val +} diff --git a/pkg/broker/receiver.go b/pkg/broker/receiver.go index 9dd264337ee..d51c3d6c755 100644 --- a/pkg/broker/receiver.go +++ b/pkg/broker/receiver.go @@ -83,10 +83,6 @@ func (r *Receiver) sendEvent(channel provisioners.ChannelReference, message *pro } func (r *Receiver) getTrigger(ctx context.Context, ref provisioners.ChannelReference) (*eventingv1alpha1.Trigger, error) { - // Sadly this doesn't work well because we do not yet have - // https://github.com/kubernetes-sigs/controller-runtime/pull/136, so controller runtime watches - // all Triggers, not just those in this namespace. And it doesn't have the RBAC (by default) for - // that to work. t := &eventingv1alpha1.Trigger{} err := r.client.Get(ctx, types.NamespacedName{ diff --git a/pkg/reconciler/v1alpha1/broker/resources/filter.go b/pkg/reconciler/v1alpha1/broker/resources/filter.go index 428d0e4a38e..21c404fae41 100644 --- a/pkg/reconciler/v1alpha1/broker/resources/filter.go +++ b/pkg/reconciler/v1alpha1/broker/resources/filter.go @@ -63,12 +63,16 @@ func MakeFilterDeployment(args *FilterArgs) *appsv1.Deployment { ServiceAccountName: args.ServiceAccountName, Containers: []corev1.Container{ { - Image: args.Image, Name: "filter", + Image: args.Image, Env: []corev1.EnvVar{ { - Name: "BROKER", - Value: args.Broker.Name, + Name: "NAMESPACE", + ValueFrom: &corev1.EnvVarSource{ + FieldRef: &corev1.ObjectFieldSelector{ + FieldPath: "metadata.namespace", + }, + }, }, }, }, diff --git a/pkg/reconciler/v1alpha1/namespace/namespace.go b/pkg/reconciler/v1alpha1/namespace/namespace.go index 483d659604d..82a72750767 100644 --- a/pkg/reconciler/v1alpha1/namespace/namespace.go +++ b/pkg/reconciler/v1alpha1/namespace/namespace.go @@ -19,11 +19,12 @@ package namespace import ( "context" "fmt" + "github.com/knative/eventing/contrib/gcppubsub/pkg/util/logging" "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" "go.uber.org/zap" - "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1" + v1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" "k8s.io/apimachinery/pkg/api/errors" k8serrors "k8s.io/apimachinery/pkg/api/errors" @@ -46,16 +47,16 @@ const ( // itself when creating events. controllerAgentName = "knative-eventing-namespace-controller" - defaultBroker = "default" - brokerFilterSA = "eventing-broker-filter" - brokerFilterRB = "eventing-broker-filter" + defaultBroker = "default" + brokerFilterSA = "eventing-broker-filter" + brokerFilterRB = "eventing-broker-filter" brokerFilterClusterRole = "eventing-broker-filter" knativeEventingAnnotation = "eventing.knative.dev/inject" // Name of the corev1.Events emitted from the reconciliation process. - brokerCreated = "BrokerCreated" - serviceAccountCreated = "BrokerFilterServiceAccountCreated" + brokerCreated = "BrokerCreated" + serviceAccountCreated = "BrokerFilterServiceAccountCreated" serviceAccountRBACCreated = "BrokerFilterServiceAccountRBACCreated" ) @@ -92,8 +93,8 @@ func ProvideController(logger *zap.Logger) func(manager.Manager) (controller.Con } // Watch all the resources that this reconciler reconciles. - for _, t := range []runtime.Object{ &corev1.ServiceAccount{}, &rbacv1.RoleBinding{}, &v1alpha1.Broker{} } { - err = c.Watch(&source.Kind{Type: t}, &handler.EnqueueRequestsFromMapFunc{ToRequests: &namespaceMapper{}}); + for _, t := range []runtime.Object{&corev1.ServiceAccount{}, &rbacv1.RoleBinding{}, &v1alpha1.Broker{}} { + err = c.Watch(&source.Kind{Type: t}, &handler.EnqueueRequestsFromMapFunc{ToRequests: &namespaceMapper{}}) if err != nil { return nil, err } @@ -228,8 +229,8 @@ func newBrokerFilterServiceAccount(ns *corev1.Namespace) *corev1.ServiceAccount return &corev1.ServiceAccount{ ObjectMeta: metav1.ObjectMeta{ Namespace: ns.Name, - Name: brokerFilterSA, - Labels: injectedLabels(), + Name: brokerFilterSA, + Labels: injectedLabels(), }, } } @@ -276,19 +277,19 @@ func newBrokerFilterRBAC(ns *corev1.Namespace, sa *corev1.ServiceAccount) *rbacv return &rbacv1.RoleBinding{ ObjectMeta: metav1.ObjectMeta{ Namespace: ns.Name, - Name: brokerFilterRB, - Labels: injectedLabels(), + Name: brokerFilterRB, + Labels: injectedLabels(), }, - RoleRef:rbacv1.RoleRef{ - APIGroup:"rbac.authorization.k8s.io", - Kind: "ClusterRole", - Name: brokerFilterClusterRole, + RoleRef: rbacv1.RoleRef{ + APIGroup: "rbac.authorization.k8s.io", + Kind: "ClusterRole", + Name: brokerFilterClusterRole, }, - Subjects:[]rbacv1.Subject{ + Subjects: []rbacv1.Subject{ { - Kind: "ServiceAccount", + Kind: "ServiceAccount", Namespace: ns.Name, - Name: sa.Name, + Name: sa.Name, }, }, } From ba726b3a26301ca49cceea8728d07e1b0f507e48 Mon Sep 17 00:00:00 2001 From: Adam Harwayne Date: Mon, 25 Feb 2019 12:41:51 -0800 Subject: [PATCH 100/221] Fix unit tests. --- .../v1alpha1/namespace/namespace_test.go | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/pkg/reconciler/v1alpha1/namespace/namespace_test.go b/pkg/reconciler/v1alpha1/namespace/namespace_test.go index 9f3364caff1..a413c87a435 100644 --- a/pkg/reconciler/v1alpha1/namespace/namespace_test.go +++ b/pkg/reconciler/v1alpha1/namespace/namespace_test.go @@ -20,6 +20,8 @@ import ( "context" "errors" "fmt" + "testing" + "github.com/google/go-cmp/cmp" "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" controllertesting "github.com/knative/eventing/pkg/reconciler/testing" @@ -35,7 +37,6 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client/fake" "sigs.k8s.io/controller-runtime/pkg/handler" "sigs.k8s.io/controller-runtime/pkg/reconcile" - "testing" ) const ( @@ -50,6 +51,13 @@ var ( // deletionTime is used when objects are marked as deleted. Rfc3339Copy() // truncates to seconds to match the loss of precision during serialization. deletionTime = metav1.Now().Rfc3339Copy() + + // map of events to set test cases' expectations easier + events = map[string]corev1.Event{ + brokerCreated: {Reason: brokerCreated, Type: corev1.EventTypeNormal}, + serviceAccountCreated: {Reason: serviceAccountCreated, Type: corev1.EventTypeNormal}, + serviceAccountRBACCreated: {Reason: serviceAccountRBACCreated, Type: corev1.EventTypeNormal}, + } ) func init() { @@ -214,6 +222,7 @@ func TestReconcile(t *testing.T) { WantAbsent: []runtime.Object{ makeBroker(), }, + WantEvent: []corev1.Event{events[serviceAccountCreated], events[serviceAccountRBACCreated]}, }, { Name: "Broker Found", @@ -222,6 +231,7 @@ func TestReconcile(t *testing.T) { makeNamespace(&trueString), makeBroker(), }, + WantEvent: []corev1.Event{events[serviceAccountCreated], events[serviceAccountRBACCreated]}, }, { Name: "Broker.Create fails", @@ -240,6 +250,7 @@ func TestReconcile(t *testing.T) { }, }, WantErrMsg: "test error creating the Broker", + WantEvent: []corev1.Event{events[serviceAccountCreated], events[serviceAccountRBACCreated]}, }, { Name: "Broker created", @@ -251,10 +262,9 @@ func TestReconcile(t *testing.T) { makeBroker(), }, WantEvent: []corev1.Event{ - { - Reason: brokerCreated, Type: corev1.EventTypeNormal, - }, - }, + events[serviceAccountCreated], + events[serviceAccountRBACCreated], + events[brokerCreated]}, }, } for _, tc := range testCases { From e7ff5b225d486230d5230e69787d1cd3bab2cc61 Mon Sep 17 00:00:00 2001 From: Adam Harwayne Date: Mon, 25 Feb 2019 12:46:46 -0800 Subject: [PATCH 101/221] Fix yaml --- config/500-controller.yaml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/config/500-controller.yaml b/config/500-controller.yaml index 48ee083917c..7dd95d66b36 100644 --- a/config/500-controller.yaml +++ b/config/500-controller.yaml @@ -35,6 +35,10 @@ spec: "-stderrthreshold", "INFO" ] env: + - name: SYSTEM_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace - name: INGRESS_IMAGE value: github.com/knative/eventing/cmd/broker/ingress - name: INGRESS_SERVICE_ACCOUNT @@ -46,11 +50,6 @@ spec: volumeMounts: - name: config-logging mountPath: /etc/config-logging - env: - - name: SYSTEM_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace volumes: - name: config-logging configMap: From dcb8774e28f48cb3280948abc4e1ca783e703ffe Mon Sep 17 00:00:00 2001 From: nachocano Date: Mon, 25 Feb 2019 14:36:39 -0800 Subject: [PATCH 102/221] Setting source to source not type. Updating comment. --- pkg/broker/receiver.go | 9 +++------ test/builders.go | 4 ++-- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/pkg/broker/receiver.go b/pkg/broker/receiver.go index 06b9b0e0f06..1644b48f442 100644 --- a/pkg/broker/receiver.go +++ b/pkg/broker/receiver.go @@ -93,12 +93,9 @@ func (r *Receiver) initClient() error { // Otherwise, on receiving an event, it may not find the trigger // and would return an error. opts := &client.ListOptions{ - Raw: &metav1.ListOptions{ - TypeMeta: metav1.TypeMeta{ - APIVersion: eventingv1alpha1.SchemeGroupVersion.String(), - Kind: "Trigger", - }, - }, + // Set Raw because if we need to get more than one page, then we will put the continue token + // into opts.Raw.Continue. + Raw: &metav1.ListOptions{}, } for { tl := &eventingv1alpha1.TriggerList{} diff --git a/test/builders.go b/test/builders.go index c73822bad4d..23d7c6538e3 100644 --- a/test/builders.go +++ b/test/builders.go @@ -60,8 +60,8 @@ func (b *TriggerBuilder) EventType(eventType string) *TriggerBuilder { return b } -func (b *TriggerBuilder) EventSource(eventType string) *TriggerBuilder { - b.Trigger.Spec.Filter.SourceAndType.Type = eventType +func (b *TriggerBuilder) EventSource(eventSource string) *TriggerBuilder { + b.Trigger.Spec.Filter.SourceAndType.Source = eventSource return b } From 71c52503aef56ab9ae2bb087f812977c359b536c Mon Sep 17 00:00:00 2001 From: Adam Harwayne Date: Tue, 26 Feb 2019 08:45:41 -0800 Subject: [PATCH 103/221] Switch from annotating the namespace to labeling it, to match Istio. --- .../v1alpha1/namespace/namespace.go | 7 ++-- .../v1alpha1/namespace/namespace_test.go | 32 +++++++++---------- test/e2e/broker_trigger_test.go | 6 ++-- test/e2e/e2e.go | 11 +++++-- 4 files changed, 31 insertions(+), 25 deletions(-) diff --git a/pkg/reconciler/v1alpha1/namespace/namespace.go b/pkg/reconciler/v1alpha1/namespace/namespace.go index 58b1bcd045e..a48cef05c19 100644 --- a/pkg/reconciler/v1alpha1/namespace/namespace.go +++ b/pkg/reconciler/v1alpha1/namespace/namespace.go @@ -52,8 +52,9 @@ const ( brokerFilterRB = "eventing-broker-filter" brokerFilterClusterRole = "eventing-broker-filter" - // Annotation to enable knative-eventing in a namespace. - knativeEventingAnnotation = "eventing.knative.dev/inject" + // Label to enable knative-eventing in a namespace. + knativeEventingLabelKey = "knative-eventing-injection" + knativeEventingLabelValue = "enabled" // Name of the corev1.Events emitted from the reconciliation process. brokerCreated = "BrokerCreated" @@ -152,7 +153,7 @@ func (r *reconciler) Reconcile(request reconcile.Request) (reconcile.Result, err return reconcile.Result{}, err } - if ns.Annotations[knativeEventingAnnotation] != "true" { + if ns.Labels[knativeEventingLabelKey] != knativeEventingLabelValue { logging.FromContext(ctx).Debug("Not reconciling Namespace") return reconcile.Result{}, nil } diff --git a/pkg/reconciler/v1alpha1/namespace/namespace_test.go b/pkg/reconciler/v1alpha1/namespace/namespace_test.go index a413c87a435..f65c8d85cae 100644 --- a/pkg/reconciler/v1alpha1/namespace/namespace_test.go +++ b/pkg/reconciler/v1alpha1/namespace/namespace_test.go @@ -45,8 +45,8 @@ const ( ) var ( - falseString = "false" - trueString = "true" + disabled = "disabled" + enabled = "enabled" // deletionTime is used when objects are marked as deleted. Rfc3339Copy() // truncates to seconds to match the loss of precision during serialization. @@ -173,7 +173,7 @@ func TestReconcile(t *testing.T) { WantErrMsg: "test error getting the NS", }, { - Name: "Namespace is not annotated", + Name: "Namespace is not labeled", Scheme: scheme.Scheme, InitialState: []runtime.Object{ makeNamespace(nil), @@ -183,10 +183,10 @@ func TestReconcile(t *testing.T) { }, }, { - Name: "Namespace is annotated off", + Name: "Namespace is labeled disabled", Scheme: scheme.Scheme, InitialState: []runtime.Object{ - makeNamespace(&falseString), + makeNamespace(&disabled), }, WantAbsent: []runtime.Object{ makeBroker(), @@ -206,7 +206,7 @@ func TestReconcile(t *testing.T) { Name: "Broker.Get fails", Scheme: scheme.Scheme, InitialState: []runtime.Object{ - makeNamespace(&trueString), + makeNamespace(&enabled), }, Mocks: controllertesting.Mocks{ MockGets: []controllertesting.MockGet{ @@ -228,7 +228,7 @@ func TestReconcile(t *testing.T) { Name: "Broker Found", Scheme: scheme.Scheme, InitialState: []runtime.Object{ - makeNamespace(&trueString), + makeNamespace(&enabled), makeBroker(), }, WantEvent: []corev1.Event{events[serviceAccountCreated], events[serviceAccountRBACCreated]}, @@ -237,7 +237,7 @@ func TestReconcile(t *testing.T) { Name: "Broker.Create fails", Scheme: scheme.Scheme, InitialState: []runtime.Object{ - makeNamespace(&trueString), + makeNamespace(&enabled), }, Mocks: controllertesting.Mocks{ MockCreates: []controllertesting.MockCreate{ @@ -256,7 +256,7 @@ func TestReconcile(t *testing.T) { Name: "Broker created", Scheme: scheme.Scheme, InitialState: []runtime.Object{ - makeNamespace(&trueString), + makeNamespace(&enabled), }, WantPresent: []runtime.Object{ makeBroker(), @@ -285,10 +285,10 @@ func TestReconcile(t *testing.T) { } } -func makeNamespace(annotationValue *string) *corev1.Namespace { - annotations := map[string]string{} - if annotationValue != nil { - annotations["eventing.knative.dev/inject"] = *annotationValue +func makeNamespace(labelValue *string) *corev1.Namespace { + labels := map[string]string{} + if labelValue != nil { + labels["knative-eventing-injection"] = *labelValue } return &corev1.Namespace{ @@ -297,14 +297,14 @@ func makeNamespace(annotationValue *string) *corev1.Namespace { Kind: "Namespace", }, ObjectMeta: metav1.ObjectMeta{ - Name: testNS, - Annotations: annotations, + Name: testNS, + Labels: labels, }, } } func makeDeletingNamespace() *corev1.Namespace { - ns := makeNamespace(&trueString) + ns := makeNamespace(&enabled) ns.DeletionTimestamp = &deletionTime return ns } diff --git a/test/e2e/broker_trigger_test.go b/test/e2e/broker_trigger_test.go index b478c673381..6deacb0e8ab 100644 --- a/test/e2e/broker_trigger_test.go +++ b/test/e2e/broker_trigger_test.go @@ -65,10 +65,10 @@ func TestDefaultBrokerWithManyTriggers(t *testing.T) { defer cleanupNS() defer TearDown(clients, cleaner, logger) - logger.Infof("Annotating namespace %s", ns) + logger.Infof("Labeling namespace %s", ns) - // Annotate namespace so that it creates the default broker. - err := AnnotateNamespace(clients, logger, map[string]string{"eventing.knative.dev/inject": "true"}) + // Label namespace so that it creates the default broker. + err := LabelNamespace(clients, logger, map[string]string{"knative-eventing-injection": "enabled"}) if err != nil { t.Fatalf("Error annotating namespace: %v", err) } diff --git a/test/e2e/e2e.go b/test/e2e/e2e.go index 98079dfe015..d4b364e4573 100644 --- a/test/e2e/e2e.go +++ b/test/e2e/e2e.go @@ -391,14 +391,19 @@ func WaitForAllTriggersReady(clients *test.Clients, logger *logging.BaseLogger, return nil } -// AnnotateNamespace annotates the test namespace with the annotations map. -func AnnotateNamespace(clients *test.Clients, logger *logging.BaseLogger, annotations map[string]string) error { +// LabelNamespace labels the test namespace with the labels map. +func LabelNamespace(clients *test.Clients, logger *logging.BaseLogger, labels map[string]string) error { ns := pkgTest.Flags.Namespace nsSpec, err := clients.Kube.Kube.CoreV1().Namespaces().Get(ns, metav1.GetOptions{}) if err != nil && errors.IsNotFound(err) { return err } - nsSpec.Annotations = annotations + if nsSpec.Labels == nil { + nsSpec.Labels = map[string]string{} + } + for k, v := range labels { + nsSpec.Labels[k] = v + } _, err = clients.Kube.Kube.CoreV1().Namespaces().Update(nsSpec) return err } From c11e25c8b5bf724d89ab0aead57dbf34e4aa33a1 Mon Sep 17 00:00:00 2001 From: nachocano Date: Tue, 26 Feb 2019 17:02:51 -0800 Subject: [PATCH 104/221] Adding EventType CRD --- b.yaml | 2 +- cmd/broker/ingress/main.go | 30 ++++- cmd/webhook/main.go | 1 + config/300-event-type.yaml | 38 ++++++ e.yaml | 8 ++ .../eventing/v1alpha1/eventtype_defaults.go | 25 ++++ pkg/apis/eventing/v1alpha1/eventtype_types.go | 116 ++++++++++++++++++ .../eventing/v1alpha1/eventtype_validation.go | 52 ++++++++ pkg/apis/eventing/v1alpha1/register.go | 2 + .../v1alpha1/zz_generated.deepcopy.go | 100 +++++++++++++++ .../eventing/v1alpha1/eventing_client.go | 5 + .../v1alpha1/fake/fake_eventing_client.go | 4 + .../eventing/v1alpha1/generated_expansion.go | 2 + .../eventing/v1alpha1/interface.go | 7 ++ .../informers/externalversions/generic.go | 2 + .../eventing/v1alpha1/expansion_generated.go | 8 ++ 16 files changed, 397 insertions(+), 5 deletions(-) create mode 100644 config/300-event-type.yaml create mode 100644 e.yaml create mode 100644 pkg/apis/eventing/v1alpha1/eventtype_defaults.go create mode 100644 pkg/apis/eventing/v1alpha1/eventtype_types.go create mode 100644 pkg/apis/eventing/v1alpha1/eventtype_validation.go diff --git a/b.yaml b/b.yaml index 595b6eb20ac..9b76f0cd481 100644 --- a/b.yaml +++ b/b.yaml @@ -7,5 +7,5 @@ spec: provisioner: apiVersion: eventing.knative.dev/v1alpha1 kind: ClusterChannelProvisioner - name: gcp-pubsub + name: inmemory diff --git a/cmd/broker/ingress/main.go b/cmd/broker/ingress/main.go index 946277c3854..3714aa8253a 100644 --- a/cmd/broker/ingress/main.go +++ b/cmd/broker/ingress/main.go @@ -25,6 +25,10 @@ import ( "os" "time" + "k8s.io/apimachinery/pkg/types" + + "sigs.k8s.io/controller-runtime/pkg/client" + eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" "github.com/knative/eventing/pkg/provisioners" "github.com/knative/pkg/signals" @@ -59,7 +63,7 @@ func main() { c := getRequiredEnv("CHANNEL") - h := NewHandler(logger, c) + h := NewHandler(logger, c, mgr.GetClient()) s := &http.Server{ Addr: ":8080", @@ -105,16 +109,18 @@ type Handler struct { receiver *provisioners.MessageReceiver dispatcher *provisioners.MessageDispatcher destination string + client client.Client logger *zap.Logger } // NewHandler creates a new ingress.Handler. -func NewHandler(logger *zap.Logger, destination string) *Handler { +func NewHandler(logger *zap.Logger, destination string, client client.Client) *Handler { handler := &Handler{ logger: logger, dispatcher: provisioners.NewMessageDispatcher(logger.Sugar()), destination: fmt.Sprintf("http://%s", destination), + client: client, } // The receiver function needs to point back at the handler itself, so set it up after // initialization. @@ -124,12 +130,28 @@ func NewHandler(logger *zap.Logger, destination string) *Handler { } func createReceiverFunction(f *Handler) func(provisioners.ChannelReference, *provisioners.Message) error { - return func(_ provisioners.ChannelReference, m *provisioners.Message) error { - // TODO Filter. + return func(c provisioners.ChannelReference, m *provisioners.Message) error { + // Using the Ce-Eventtype header as the name + name := m.Headers["Ce-Eventtype"] + _, err := f.getEventType(c.Namespace, name) + if err != nil { + f.logger.Error("Error getting EventType", zap.String("name", name)) + return nil + } return f.dispatch(m) } } +func (f *Handler) getEventType(namespace, name string) (*eventingv1alpha1.EventType, error) { + eventType := &eventingv1alpha1.EventType{} + namespacedName := types.NamespacedName{ + Namespace: namespace, + Name: name, + } + err := f.client.Get(context.Background(), namespacedName, eventType) + return eventType, err +} + func (f *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { f.receiver.HandleRequest(w, r) } diff --git a/cmd/webhook/main.go b/cmd/webhook/main.go index c82ab87a6dd..80f323e9c9b 100644 --- a/cmd/webhook/main.go +++ b/cmd/webhook/main.go @@ -101,6 +101,7 @@ func main() { eventingv1alpha1.SchemeGroupVersion.WithKind("ClusterChannelProvisioner"): &eventingv1alpha1.ClusterChannelProvisioner{}, eventingv1alpha1.SchemeGroupVersion.WithKind("Subscription"): &eventingv1alpha1.Subscription{}, eventingv1alpha1.SchemeGroupVersion.WithKind("Trigger"): &eventingv1alpha1.Trigger{}, + eventingv1alpha1.SchemeGroupVersion.WithKind("EventType"): &eventingv1alpha1.EventType{}, }, Logger: logger, } diff --git a/config/300-event-type.yaml b/config/300-event-type.yaml new file mode 100644 index 00000000000..f876a3b7027 --- /dev/null +++ b/config/300-event-type.yaml @@ -0,0 +1,38 @@ +# Copyright 2019 The Knative Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: event-types.eventing.knative.dev +spec: + group: eventing.knative.dev + version: v1alpha1 + names: + kind: Event-Type + plural: event-types + singular: event-type + categories: + - all + - knative + - eventing + scope: Namespaced + subresources: + status: {} + additionalPrinterColumns: + - name: Origin + type: string + JSONPath: ".spec.origin" + - name: Schema + type: string + JSONPath: ".spec.schema" diff --git a/e.yaml b/e.yaml new file mode 100644 index 00000000000..de7b211a7de --- /dev/null +++ b/e.yaml @@ -0,0 +1,8 @@ +apiVersion: eventing.knative.dev/v1alpha1 +kind: Event-Type +metadata: + name: com.github.pullrequest +spec: + origin: github.com + schema: http://foo2.example/schema + diff --git a/pkg/apis/eventing/v1alpha1/eventtype_defaults.go b/pkg/apis/eventing/v1alpha1/eventtype_defaults.go new file mode 100644 index 00000000000..8b29c76df41 --- /dev/null +++ b/pkg/apis/eventing/v1alpha1/eventtype_defaults.go @@ -0,0 +1,25 @@ +/* +Copyright 2018 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +func (et *EventType) SetDefaults() { + et.Spec.SetDefaults(et.Name) +} + +func (ets *EventTypeSpec) SetDefaults(eventTypeName string) { + // TODO anything? +} diff --git a/pkg/apis/eventing/v1alpha1/eventtype_types.go b/pkg/apis/eventing/v1alpha1/eventtype_types.go new file mode 100644 index 00000000000..2cc0f0fe343 --- /dev/null +++ b/pkg/apis/eventing/v1alpha1/eventtype_types.go @@ -0,0 +1,116 @@ +/* + * Copyright 2019 The Knative Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package v1alpha1 + +import ( + "github.com/knative/pkg/apis" + duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" + "github.com/knative/pkg/webhook" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +// +genclient +// +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 + Status EventTypeStatus `json:"status,omitempty"` +} + +// Check that EventType can be validated, can be defaulted, and has immutable fields. +var _ apis.Validatable = (*EventType)(nil) +var _ apis.Defaultable = (*EventType)(nil) +var _ apis.Immutable = (*EventType)(nil) +var _ runtime.Object = (*EventType)(nil) +var _ webhook.GenericCRD = (*EventType)(nil) + +type EventTypeSpec struct { + // TODO By enabling the status subresource metadata.generation should increment + // thus making this property obsolete. + // + // We should be able to drop this property with a CRD conversion webhook + // in the future + // + // +optional + DeprecatedGeneration int64 `json:"generation,omitempty"` + + Origin string `json:"origin,omitempty"` + // +optional + Schema string `json:"schema,omitempty"` +} + +var eventTypeCondSet = duckv1alpha1.NewLivingConditionSet(EventTypeConditionReady) + +// EventTypeStatus represents the current state of a EventType. +type EventTypeStatus struct { + // ObservedGeneration is the most recent generation observed for this EventType. + // It corresponds to the Broker's generation, which is updated on mutation by + // the API Server. + // TODO: The above comment is only true once + // https://github.com/kubernetes/kubernetes/issues/58778 is fixed. + // +optional + ObservedGeneration int64 `json:"observedGeneration,omitempty"` + + // Represents the latest available observations of a event type's current state. + // +optional + // +patchMergeKey=type + // +patchStrategy=merge + Conditions duckv1alpha1.Conditions `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"` +} + +const ( + EventTypeConditionReady = duckv1alpha1.ConditionReady +) + +// GetCondition returns the condition currently associated with the given type, or nil. +func (et *EventTypeStatus) GetCondition(t duckv1alpha1.ConditionType) *duckv1alpha1.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() +} + +// InitializeConditions sets relevant unset conditions to Unknown state. +func (et *EventTypeStatus) InitializeConditions() { + eventTypeCondSet.Manage(et).InitializeConditions() +} + +func (rs *EventTypeStatus) MarkEventTypeReady() { + eventTypeCondSet.Manage(rs).MarkTrue(EventTypeConditionReady) +} + +// +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"` +} diff --git a/pkg/apis/eventing/v1alpha1/eventtype_validation.go b/pkg/apis/eventing/v1alpha1/eventtype_validation.go new file mode 100644 index 00000000000..b7b9a82502d --- /dev/null +++ b/pkg/apis/eventing/v1alpha1/eventtype_validation.go @@ -0,0 +1,52 @@ +/* +Copyright 2018 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + "github.com/google/go-cmp/cmp" + "github.com/knative/pkg/apis" +) + +func (et *EventType) Validate() *apis.FieldError { + return et.Spec.Validate().ViaField("spec") +} + +func (et *EventTypeSpec) Validate() *apis.FieldError { + var errs *apis.FieldError + return errs +} + +func (r *EventType) CheckImmutableFields(og apis.Immutable) *apis.FieldError { + if og == nil { + return nil + } + + original, ok := og.(*EventType) + if !ok { + return &apis.FieldError{Message: "The provided original was not an EventType"} + } + + // TODO check other fields. + if diff := cmp.Diff(original.Spec.Origin, r.Spec.Origin); diff != "" { + return &apis.FieldError{ + Message: "Immutable fields changed (-old +new)", + Paths: []string{"spec", "events"}, + Details: diff, + } + } + return nil +} diff --git a/pkg/apis/eventing/v1alpha1/register.go b/pkg/apis/eventing/v1alpha1/register.go index fb3a5292623..977cad56aaf 100644 --- a/pkg/apis/eventing/v1alpha1/register.go +++ b/pkg/apis/eventing/v1alpha1/register.go @@ -55,6 +55,8 @@ func addKnownTypes(scheme *runtime.Scheme) error { &SubscriptionList{}, &Trigger{}, &TriggerList{}, + &EventType{}, + &EventTypeList{}, ) metav1.AddToGroupVersion(scheme, SchemeGroupVersion) return nil diff --git a/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go index 44ba2ee9196..7a6a4ba6884 100644 --- a/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go @@ -374,6 +374,106 @@ func (in *ClusterChannelProvisionerStatus) DeepCopy() *ClusterChannelProvisioner 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) + out.Spec = in.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 + out.ListMeta = in.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 + 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 + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make(duck_v1alpha1.Conditions, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + 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 *ReplyStrategy) DeepCopyInto(out *ReplyStrategy) { *out = *in diff --git a/pkg/client/clientset/versioned/typed/eventing/v1alpha1/eventing_client.go b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/eventing_client.go index 753d1081b84..033b408a70d 100644 --- a/pkg/client/clientset/versioned/typed/eventing/v1alpha1/eventing_client.go +++ b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/eventing_client.go @@ -30,6 +30,7 @@ type EventingV1alpha1Interface interface { BrokersGetter ChannelsGetter ClusterChannelProvisionersGetter + EventTypesGetter SubscriptionsGetter TriggersGetter } @@ -51,6 +52,10 @@ func (c *EventingV1alpha1Client) ClusterChannelProvisioners() ClusterChannelProv return newClusterChannelProvisioners(c) } +func (c *EventingV1alpha1Client) EventTypes(namespace string) EventTypeInterface { + return newEventTypes(c, namespace) +} + func (c *EventingV1alpha1Client) Subscriptions(namespace string) SubscriptionInterface { return newSubscriptions(c, namespace) } diff --git a/pkg/client/clientset/versioned/typed/eventing/v1alpha1/fake/fake_eventing_client.go b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/fake/fake_eventing_client.go index 4362e785f5a..c14e2b271de 100644 --- a/pkg/client/clientset/versioned/typed/eventing/v1alpha1/fake/fake_eventing_client.go +++ b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/fake/fake_eventing_client.go @@ -40,6 +40,10 @@ func (c *FakeEventingV1alpha1) ClusterChannelProvisioners() v1alpha1.ClusterChan return &FakeClusterChannelProvisioners{c} } +func (c *FakeEventingV1alpha1) EventTypes(namespace string) v1alpha1.EventTypeInterface { + return &FakeEventTypes{c, namespace} +} + func (c *FakeEventingV1alpha1) Subscriptions(namespace string) v1alpha1.SubscriptionInterface { return &FakeSubscriptions{c, namespace} } diff --git a/pkg/client/clientset/versioned/typed/eventing/v1alpha1/generated_expansion.go b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/generated_expansion.go index 2f88fb3320b..d5e32edbc08 100644 --- a/pkg/client/clientset/versioned/typed/eventing/v1alpha1/generated_expansion.go +++ b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/generated_expansion.go @@ -24,6 +24,8 @@ type ChannelExpansion interface{} type ClusterChannelProvisionerExpansion interface{} +type EventTypeExpansion interface{} + type SubscriptionExpansion interface{} type TriggerExpansion interface{} diff --git a/pkg/client/informers/externalversions/eventing/v1alpha1/interface.go b/pkg/client/informers/externalversions/eventing/v1alpha1/interface.go index 29ad6f191f0..d272412d038 100644 --- a/pkg/client/informers/externalversions/eventing/v1alpha1/interface.go +++ b/pkg/client/informers/externalversions/eventing/v1alpha1/interface.go @@ -30,6 +30,8 @@ type Interface interface { Channels() ChannelInformer // ClusterChannelProvisioners returns a ClusterChannelProvisionerInformer. ClusterChannelProvisioners() ClusterChannelProvisionerInformer + // EventTypes returns a EventTypeInformer. + EventTypes() EventTypeInformer // Subscriptions returns a SubscriptionInformer. Subscriptions() SubscriptionInformer // Triggers returns a TriggerInformer. @@ -62,6 +64,11 @@ func (v *version) ClusterChannelProvisioners() ClusterChannelProvisionerInformer return &clusterChannelProvisionerInformer{factory: v.factory, tweakListOptions: v.tweakListOptions} } +// EventTypes returns a EventTypeInformer. +func (v *version) EventTypes() EventTypeInformer { + return &eventTypeInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} + // Subscriptions returns a SubscriptionInformer. func (v *version) Subscriptions() SubscriptionInformer { return &subscriptionInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} diff --git a/pkg/client/informers/externalversions/generic.go b/pkg/client/informers/externalversions/generic.go index 6c22f720af9..a4cc267b091 100644 --- a/pkg/client/informers/externalversions/generic.go +++ b/pkg/client/informers/externalversions/generic.go @@ -59,6 +59,8 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource return &genericInformer{resource: resource.GroupResource(), informer: f.Eventing().V1alpha1().Channels().Informer()}, nil case v1alpha1.SchemeGroupVersion.WithResource("clusterchannelprovisioners"): return &genericInformer{resource: resource.GroupResource(), informer: f.Eventing().V1alpha1().ClusterChannelProvisioners().Informer()}, nil + case v1alpha1.SchemeGroupVersion.WithResource("eventtypes"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Eventing().V1alpha1().EventTypes().Informer()}, nil case v1alpha1.SchemeGroupVersion.WithResource("subscriptions"): return &genericInformer{resource: resource.GroupResource(), informer: f.Eventing().V1alpha1().Subscriptions().Informer()}, nil case v1alpha1.SchemeGroupVersion.WithResource("triggers"): diff --git a/pkg/client/listers/eventing/v1alpha1/expansion_generated.go b/pkg/client/listers/eventing/v1alpha1/expansion_generated.go index 2a49e1b434b..66326fa3477 100644 --- a/pkg/client/listers/eventing/v1alpha1/expansion_generated.go +++ b/pkg/client/listers/eventing/v1alpha1/expansion_generated.go @@ -38,6 +38,14 @@ type ChannelNamespaceListerExpansion interface{} // ClusterChannelProvisionerLister. type ClusterChannelProvisionerListerExpansion 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{} + // SubscriptionListerExpansion allows custom methods to be added to // SubscriptionLister. type SubscriptionListerExpansion interface{} From 251ce2a8219b6dbe618cfe22fd44216a514bfe86 Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Tue, 26 Feb 2019 18:43:16 -0800 Subject: [PATCH 105/221] Update to type --- config/{300-event-type.yaml => 300-eventtype.yaml} | 2 +- e.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename config/{300-event-type.yaml => 300-eventtype.yaml} (98%) diff --git a/config/300-event-type.yaml b/config/300-eventtype.yaml similarity index 98% rename from config/300-event-type.yaml rename to config/300-eventtype.yaml index f876a3b7027..682e84e943a 100644 --- a/config/300-event-type.yaml +++ b/config/300-eventtype.yaml @@ -19,7 +19,7 @@ spec: group: eventing.knative.dev version: v1alpha1 names: - kind: Event-Type + kind: EventType plural: event-types singular: event-type categories: diff --git a/e.yaml b/e.yaml index de7b211a7de..43a7cd8c5ef 100644 --- a/e.yaml +++ b/e.yaml @@ -1,5 +1,5 @@ apiVersion: eventing.knative.dev/v1alpha1 -kind: Event-Type +kind: EventType metadata: name: com.github.pullrequest spec: From 6f68670cf91ef78974a5b102619bb9f29fe5060e Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Tue, 26 Feb 2019 19:06:53 -0800 Subject: [PATCH 106/221] Updates --- cmd/broker/ingress/main.go | 4 ++-- config/300-eventtype.yaml | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cmd/broker/ingress/main.go b/cmd/broker/ingress/main.go index 3714aa8253a..fa7acfef307 100644 --- a/cmd/broker/ingress/main.go +++ b/cmd/broker/ingress/main.go @@ -136,7 +136,7 @@ func createReceiverFunction(f *Handler) func(provisioners.ChannelReference, *pro _, err := f.getEventType(c.Namespace, name) if err != nil { f.logger.Error("Error getting EventType", zap.String("name", name)) - return nil + return err } return f.dispatch(m) } @@ -148,7 +148,7 @@ func (f *Handler) getEventType(namespace, name string) (*eventingv1alpha1.EventT Namespace: namespace, Name: name, } - err := f.client.Get(context.Background(), namespacedName, eventType) + err := f.client.Get(context.TODO(), namespacedName, eventType) return eventType, err } diff --git a/config/300-eventtype.yaml b/config/300-eventtype.yaml index 682e84e943a..6788a343039 100644 --- a/config/300-eventtype.yaml +++ b/config/300-eventtype.yaml @@ -14,14 +14,14 @@ apiVersion: apiextensions.k8s.io/v1beta1 kind: CustomResourceDefinition metadata: - name: event-types.eventing.knative.dev + name: eventtypes.eventing.knative.dev spec: group: eventing.knative.dev version: v1alpha1 names: kind: EventType - plural: event-types - singular: event-type + plural: eventtypes + singular: eventtype categories: - all - knative From b69d6ea47246424fe2c7c8ab2e5ef1ba861ed4a1 Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Wed, 27 Feb 2019 09:36:54 -0800 Subject: [PATCH 107/221] updating eventtypes to event-types --- config/300-eventtype.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/config/300-eventtype.yaml b/config/300-eventtype.yaml index 6788a343039..682e84e943a 100644 --- a/config/300-eventtype.yaml +++ b/config/300-eventtype.yaml @@ -14,14 +14,14 @@ apiVersion: apiextensions.k8s.io/v1beta1 kind: CustomResourceDefinition metadata: - name: eventtypes.eventing.knative.dev + name: event-types.eventing.knative.dev spec: group: eventing.knative.dev version: v1alpha1 names: kind: EventType - plural: eventtypes - singular: eventtype + plural: event-types + singular: event-type categories: - all - knative From 833b77dddf5ec669265ce1f0c749cc3793894c35 Mon Sep 17 00:00:00 2001 From: nachocano Date: Wed, 27 Feb 2019 10:40:04 -0800 Subject: [PATCH 108/221] Ingress policy --- cmd/broker/ingress/main.go | 45 ++++++++----------- config/500-controller.yaml | 2 + pkg/broker/ingress.go | 88 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 107 insertions(+), 28 deletions(-) create mode 100644 pkg/broker/ingress.go diff --git a/cmd/broker/ingress/main.go b/cmd/broker/ingress/main.go index fa7acfef307..de2872f1ea6 100644 --- a/cmd/broker/ingress/main.go +++ b/cmd/broker/ingress/main.go @@ -25,7 +25,7 @@ import ( "os" "time" - "k8s.io/apimachinery/pkg/types" + "github.com/knative/eventing/pkg/broker" "sigs.k8s.io/controller-runtime/pkg/client" @@ -62,8 +62,9 @@ func main() { } c := getRequiredEnv("CHANNEL") + policy := getRequiredEnv("INGRESS_POLICY") - h := NewHandler(logger, c, mgr.GetClient()) + h := NewHandler(logger, c, policy, mgr.GetClient()) s := &http.Server{ Addr: ":8080", @@ -106,21 +107,23 @@ func getRequiredEnv(envKey string) string { // http.Handler that takes a single request in and sends it out to a single destination. type Handler struct { - receiver *provisioners.MessageReceiver - dispatcher *provisioners.MessageDispatcher - destination string - client client.Client + receiver *provisioners.MessageReceiver + dispatcher *provisioners.MessageDispatcher + ingressPolicy broker.IngressPolicy + destination string + client client.Client logger *zap.Logger } // NewHandler creates a new ingress.Handler. -func NewHandler(logger *zap.Logger, destination string, client client.Client) *Handler { +func NewHandler(logger *zap.Logger, destination, policy string, client client.Client) *Handler { handler := &Handler{ - logger: logger, - dispatcher: provisioners.NewMessageDispatcher(logger.Sugar()), - destination: fmt.Sprintf("http://%s", destination), - client: client, + logger: logger, + dispatcher: provisioners.NewMessageDispatcher(logger.Sugar()), + ingressPolicy: broker.NewIngressPolicy(logger.Sugar(), client, policy), + destination: fmt.Sprintf("http://%s", destination), + client: client, } // The receiver function needs to point back at the handler itself, so set it up after // initialization. @@ -131,27 +134,13 @@ func NewHandler(logger *zap.Logger, destination string, client client.Client) *H func createReceiverFunction(f *Handler) func(provisioners.ChannelReference, *provisioners.Message) error { return func(c provisioners.ChannelReference, m *provisioners.Message) error { - // Using the Ce-Eventtype header as the name - name := m.Headers["Ce-Eventtype"] - _, err := f.getEventType(c.Namespace, name) - if err != nil { - f.logger.Error("Error getting EventType", zap.String("name", name)) - return err + if f.ingressPolicy.AllowMessage(c.Namespace, m) { + return f.dispatch(m) } - return f.dispatch(m) + return nil } } -func (f *Handler) getEventType(namespace, name string) (*eventingv1alpha1.EventType, error) { - eventType := &eventingv1alpha1.EventType{} - namespacedName := types.NamespacedName{ - Namespace: namespace, - Name: name, - } - err := f.client.Get(context.TODO(), namespacedName, eventType) - return eventType, err -} - func (f *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { f.receiver.HandleRequest(w, r) } diff --git a/config/500-controller.yaml b/config/500-controller.yaml index 7dd95d66b36..b8c81e74236 100644 --- a/config/500-controller.yaml +++ b/config/500-controller.yaml @@ -43,6 +43,8 @@ spec: value: github.com/knative/eventing/cmd/broker/ingress - name: INGRESS_SERVICE_ACCOUNT value: default + - name: INGRESS_POLICY + value: allow_any - name: FILTER_IMAGE value: github.com/knative/eventing/cmd/broker/filter - name: FILTER_SERVICE_ACCOUNT diff --git a/pkg/broker/ingress.go b/pkg/broker/ingress.go new file mode 100644 index 00000000000..0aef1fdc3c3 --- /dev/null +++ b/pkg/broker/ingress.go @@ -0,0 +1,88 @@ +/* + * Copyright 2018 The Knative Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 broker + +import ( + "context" + + eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" + "github.com/knative/eventing/pkg/provisioners" + "go.uber.org/zap" + k8serrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +const ( + allowAny = "allow_any" + allowRegisteredTypes = "allow_registered_types" +) + +type IngressPolicy interface { + AllowMessage(namespace string, message *provisioners.Message) bool +} + +type AllowAnyPolicy struct{} + +type AllowRegisteredTypesPolicy struct { + logger *zap.SugaredLogger + client client.Client +} + +func NewIngressPolicy(logger *zap.SugaredLogger, client client.Client, policy string) IngressPolicy { + return newIngressPolicy(logger, client, policy) +} + +func newIngressPolicy(logger *zap.SugaredLogger, client client.Client, policy string) IngressPolicy { + switch policy { + case allowRegisteredTypes: + return &AllowRegisteredTypesPolicy{ + logger: logger, + client: client, + } + case allowAny: + return &AllowAnyPolicy{} + default: + return &AllowAnyPolicy{} + } +} + +func (policy *AllowAnyPolicy) AllowMessage(namespace string, message *provisioners.Message) bool { + return true +} + +func (policy *AllowRegisteredTypesPolicy) AllowMessage(namespace string, message *provisioners.Message) bool { + eventType := &eventingv1alpha1.EventType{} + name := message.Headers["Ce-Eventtype"] + + err := policy.client.Get(context.TODO(), + types.NamespacedName{ + Namespace: namespace, + Name: name, + }, + eventType) + + if k8serrors.IsNotFound(err) { + policy.logger.Error("EventType not found", zap.String("type", name)) + return false + } else if err != nil { + policy.logger.Error("Error getting EventType", zap.String("type", name)) + return false + } else { + return true + } +} From d6a32c8ebe5bdbe2bc0069339bd96d44a10ff23e Mon Sep 17 00:00:00 2001 From: nachocano Date: Wed, 27 Feb 2019 11:15:26 -0800 Subject: [PATCH 109/221] Updating environment variables --- b.yaml | 2 +- cmd/broker/ingress/main.go | 2 +- cmd/controller/main.go | 10 +++++- pkg/reconciler/v1alpha1/broker/broker.go | 34 ++++++++++--------- .../v1alpha1/broker/resources/ingress.go | 5 +++ 5 files changed, 34 insertions(+), 19 deletions(-) diff --git a/b.yaml b/b.yaml index 9b76f0cd481..54ad31cbd23 100644 --- a/b.yaml +++ b/b.yaml @@ -7,5 +7,5 @@ spec: provisioner: apiVersion: eventing.knative.dev/v1alpha1 kind: ClusterChannelProvisioner - name: inmemory + name: in-memory-channel diff --git a/cmd/broker/ingress/main.go b/cmd/broker/ingress/main.go index de2872f1ea6..c26deaad01a 100644 --- a/cmd/broker/ingress/main.go +++ b/cmd/broker/ingress/main.go @@ -62,7 +62,7 @@ func main() { } c := getRequiredEnv("CHANNEL") - policy := getRequiredEnv("INGRESS_POLICY") + policy := getRequiredEnv("POLICY") h := NewHandler(logger, c, policy, mgr.GetClient()) diff --git a/cmd/controller/main.go b/cmd/controller/main.go index 382e79d38a7..d4d8a4bf488 100644 --- a/cmd/controller/main.go +++ b/cmd/controller/main.go @@ -119,11 +119,19 @@ func main() { } } + envVariables := broker.EnvVariables{ + IngressImage: getRequiredEnv("INGRESS_IMAGE"), + IngressServiceAccountName: getRequiredEnv("INGRESS_SERVICE_ACCOUNT"), + IngressPolicy: getRequiredEnv("INGRESS_POLICY"), + FilterImage: getRequiredEnv("FILTER_IMAGE"), + FilterServiceAccountName: getRequiredEnv("FILTER_SERVICE_ACCOUNT"), + } + // Add each controller's ProvideController func to this list to have the // manager run it. providers := []ProvideFunc{ subscription.ProvideController, - broker.ProvideController(logger.Desugar(), getRequiredEnv("INGRESS_IMAGE"), getRequiredEnv("INGRESS_SERVICE_ACCOUNT"), getRequiredEnv("FILTER_IMAGE"), getRequiredEnv("FILTER_SERVICE_ACCOUNT")), + broker.ProvideController(logger.Desugar(), envVariables), trigger.ProvideController(logger.Desugar()), namespace.ProvideController(logger.Desugar()), } diff --git a/pkg/reconciler/v1alpha1/broker/broker.go b/pkg/reconciler/v1alpha1/broker/broker.go index d72c63cff34..b9be06eeb90 100644 --- a/pkg/reconciler/v1alpha1/broker/broker.go +++ b/pkg/reconciler/v1alpha1/broker/broker.go @@ -74,28 +74,29 @@ type reconciler struct { logger *zap.Logger - ingressImage string - ingressServiceAccountName string - filterImage string - filterServiceAccountName string + envVariables EnvVariables +} + +type EnvVariables struct { + IngressImage string + IngressServiceAccountName string + IngressPolicy string + FilterImage string + FilterServiceAccountName string } // Verify the struct implements reconcile.Reconciler. var _ reconcile.Reconciler = &reconciler{} // ProvideController returns a function that returns a Broker controller. -func ProvideController(logger *zap.Logger, ingressImage, ingressServiceAccount, filterImage, filterServiceAccount string) func(manager.Manager) (controller.Controller, error) { +func ProvideController(logger *zap.Logger, envVariables EnvVariables) func(manager.Manager) (controller.Controller, error) { return func(mgr manager.Manager) (controller.Controller, error) { // Setup a new controller to Reconcile Brokers. c, err := controller.New(controllerAgentName, mgr, controller.Options{ Reconciler: &reconciler{ - recorder: mgr.GetRecorder(controllerAgentName), - logger: logger, - - ingressImage: ingressImage, - ingressServiceAccountName: ingressServiceAccount, - filterImage: filterImage, - filterServiceAccountName: filterServiceAccount, + recorder: mgr.GetRecorder(controllerAgentName), + logger: logger, + envVariables: envVariables, }, }) if err != nil { @@ -270,8 +271,8 @@ func (r *reconciler) updateStatus(broker *v1alpha1.Broker) (*v1alpha1.Broker, er func (r *reconciler) reconcileFilterDeployment(ctx context.Context, b *v1alpha1.Broker) (*v1.Deployment, error) { expected := resources.MakeFilterDeployment(&resources.FilterArgs{ Broker: b, - Image: r.filterImage, - ServiceAccountName: r.filterServiceAccountName, + Image: r.envVariables.FilterImage, + ServiceAccountName: r.envVariables.FilterServiceAccountName, }) return r.reconcileDeployment(ctx, expected) } @@ -434,8 +435,9 @@ func (r *reconciler) reconcileService(ctx context.Context, svc *corev1.Service) func (r *reconciler) reconcileIngressDeployment(ctx context.Context, b *v1alpha1.Broker, c *v1alpha1.Channel) (*v1.Deployment, error) { expected := resources.MakeIngress(&resources.IngressArgs{ Broker: b, - Image: r.ingressImage, - ServiceAccountName: r.ingressServiceAccountName, + Image: r.envVariables.IngressImage, + ServiceAccountName: r.envVariables.IngressServiceAccountName, + Policy: r.envVariables.IngressPolicy, ChannelAddress: c.Status.Address.Hostname, }) return r.reconcileDeployment(ctx, expected) diff --git a/pkg/reconciler/v1alpha1/broker/resources/ingress.go b/pkg/reconciler/v1alpha1/broker/resources/ingress.go index 406f1b85daa..4a750390acc 100644 --- a/pkg/reconciler/v1alpha1/broker/resources/ingress.go +++ b/pkg/reconciler/v1alpha1/broker/resources/ingress.go @@ -31,6 +31,7 @@ import ( type IngressArgs struct { Broker *eventingv1alpha1.Broker Image string + Policy string ServiceAccountName string ChannelAddress string } @@ -75,6 +76,10 @@ func MakeIngress(args *IngressArgs) *appsv1.Deployment { Name: "CHANNEL", Value: args.ChannelAddress, }, + { + Name: "POLICY", + Value: args.Policy, + }, }, }, }, From 4c6b1d912dac1ef93873f6ff9aea3ddee5b8398e Mon Sep 17 00:00:00 2001 From: nachocano Date: Wed, 27 Feb 2019 11:46:01 -0800 Subject: [PATCH 110/221] yamls to give event-type permissions --- config/200-eventtype-clusterrole.yaml | 28 +++++++++++++++++++++ config/201-eventype-clusterrolebinding.yaml | 26 +++++++++++++++++++ config/500-controller.yaml | 2 +- 3 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 config/200-eventtype-clusterrole.yaml create mode 100644 config/201-eventype-clusterrolebinding.yaml diff --git a/config/200-eventtype-clusterrole.yaml b/config/200-eventtype-clusterrole.yaml new file mode 100644 index 00000000000..395ba8aa54d --- /dev/null +++ b/config/200-eventtype-clusterrole.yaml @@ -0,0 +1,28 @@ +# Copyright 2019 The Knative Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: eventing-event-type +rules: + - apiGroups: + - eventing.knative.dev + resources: + - event-types + - event-types/status + verbs: + - get + - list + - watch diff --git a/config/201-eventype-clusterrolebinding.yaml b/config/201-eventype-clusterrolebinding.yaml new file mode 100644 index 00000000000..1425fa03975 --- /dev/null +++ b/config/201-eventype-clusterrolebinding.yaml @@ -0,0 +1,26 @@ +# Copyright 2018 The Knative Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: eventing-ingress-eventtype +subjects: + - kind: ServiceAccount + name: default + namespace: default +roleRef: + kind: ClusterRole + name: eventing-event-type + apiGroup: rbac.authorization.k8s.io + diff --git a/config/500-controller.yaml b/config/500-controller.yaml index b8c81e74236..e77c1bcfda7 100644 --- a/config/500-controller.yaml +++ b/config/500-controller.yaml @@ -44,7 +44,7 @@ spec: - name: INGRESS_SERVICE_ACCOUNT value: default - name: INGRESS_POLICY - value: allow_any + value: allow_registered_types - name: FILTER_IMAGE value: github.com/knative/eventing/cmd/broker/filter - name: FILTER_SERVICE_ACCOUNT From 8d6df67cd7ed5dc977257d5a8d08ce8c867c1ac6 Mon Sep 17 00:00:00 2001 From: Adam Harwayne Date: Wed, 27 Feb 2019 13:34:51 -0800 Subject: [PATCH 111/221] General clean up. --- cmd/broker/filter/main.go | 10 +-- cmd/broker/ingress/main.go | 15 ++-- cmd/controller/main.go | 8 +- cmd/webhook/main.go | 14 ++-- config/500-controller.yaml | 8 +- pkg/apis/eventing/v1alpha1/broker_types.go | 15 ++-- .../eventing/v1alpha1/broker_types_test.go | 2 +- .../eventing/v1alpha1/broker_validation.go | 7 +- .../eventing/v1alpha1/trigger_defaults.go | 14 +++- pkg/apis/eventing/v1alpha1/trigger_types.go | 14 +++- .../eventing/v1alpha1/trigger_types_test.go | 2 +- pkg/broker/receiver.go | 26 +++--- pkg/broker/receiver_test.go | 11 ++- pkg/reconciler/v1alpha1/broker/broker.go | 56 ++++++------- pkg/reconciler/v1alpha1/broker/broker_test.go | 68 +++++---------- .../v1alpha1/broker/resources/filter.go | 2 +- .../v1alpha1/broker/resources/ingress.go | 2 +- .../v1alpha1/namespace/namespace.go | 32 +++---- .../v1alpha1/namespace/namespace_test.go | 41 +-------- pkg/reconciler/v1alpha1/trigger/trigger.go | 83 +++++++------------ .../v1alpha1/trigger/trigger_test.go | 9 +- 21 files changed, 188 insertions(+), 251 deletions(-) diff --git a/cmd/broker/filter/main.go b/cmd/broker/filter/main.go index 8382060256c..f60b33340e0 100644 --- a/cmd/broker/filter/main.go +++ b/cmd/broker/filter/main.go @@ -1,5 +1,5 @@ /* - * Copyright 2018 The Knative Authors + * Copyright 2019 The Knative Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -52,20 +52,19 @@ func main() { logger.Fatal("Error starting up.", zap.Error(err)) } - // Add custom types to this array to get them into the manager's scheme. if err = eventingv1alpha1.AddToScheme(mgr.GetScheme()); err != nil { logger.Fatal("Unable to add eventingv1alpha1 scheme", zap.Error(err)) } - // We are running both the receiver (takes messages in from the cluster) and the dispatcher (send the messages - // to the triggers' subscribers) in this binary. + // We are running both the receiver (takes messages in from the Broker) and the dispatcher (send + // the messages to the triggers' subscribers) in this binary. _, runnable := broker.New(logger, mgr.GetClient()) err = mgr.Add(runnable) if err != nil { logger.Fatal("Unable to start the receivers runnable", zap.Error(err), zap.Any("runnable", runnable)) } - // set up signals so we handle the first shutdown signal gracefully + // Set up signals so we handle the first shutdown signal gracefully. stopCh := signals.SetupSignalHandler() // Start blocks forever. @@ -74,6 +73,7 @@ func main() { if err != nil { logger.Fatal("Manager.Start() returned an error", zap.Error(err)) } + logger.Info("Exiting...") } func getRequiredEnv(envKey string) string { diff --git a/cmd/broker/ingress/main.go b/cmd/broker/ingress/main.go index 946277c3854..6027e82d5d9 100644 --- a/cmd/broker/ingress/main.go +++ b/cmd/broker/ingress/main.go @@ -1,5 +1,5 @@ /* - * Copyright 2018 The Knative Authors + * Copyright 2019 The Knative Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,6 +34,8 @@ import ( ) var ( + port = 8080 + readTimeout = 1 * time.Minute writeTimeout = 1 * time.Minute ) @@ -51,10 +53,8 @@ func main() { logger.Fatal("Error starting up.", zap.Error(err)) } - // Add custom types to this array to get them into the manager's scheme. - err = eventingv1alpha1.AddToScheme(mgr.GetScheme()) - if err != nil { - logger.Fatal("Unable to add scheme", zap.Error(err)) + if err = eventingv1alpha1.AddToScheme(mgr.GetScheme()); err != nil { + logger.Fatal("Unable to add eventingv1alpha1 scheme", zap.Error(err)) } c := getRequiredEnv("CHANNEL") @@ -62,7 +62,7 @@ func main() { h := NewHandler(logger, c) s := &http.Server{ - Addr: ":8080", + Addr: fmt.Sprintf(":%d", port), Handler: h, ErrorLog: zap.NewStdLog(logger), ReadTimeout: readTimeout, @@ -74,7 +74,7 @@ func main() { s: s, }) if err != nil { - logger.Fatal("Unable to add ListenAndServe", zap.Error(err)) + logger.Fatal("Unable to add runnableServer", zap.Error(err)) } // Set up signals so we handle the first shutdown signal gracefully. @@ -130,6 +130,7 @@ func createReceiverFunction(f *Handler) func(provisioners.ChannelReference, *pro } } +// http.Handler interface. func (f *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { f.receiver.HandleRequest(w, r) } diff --git a/cmd/controller/main.go b/cmd/controller/main.go index 382e79d38a7..60c46d4d967 100644 --- a/cmd/controller/main.go +++ b/cmd/controller/main.go @@ -123,7 +123,13 @@ func main() { // manager run it. providers := []ProvideFunc{ subscription.ProvideController, - broker.ProvideController(logger.Desugar(), getRequiredEnv("INGRESS_IMAGE"), getRequiredEnv("INGRESS_SERVICE_ACCOUNT"), getRequiredEnv("FILTER_IMAGE"), getRequiredEnv("FILTER_SERVICE_ACCOUNT")), + broker.ProvideController(logger.Desugar(), + broker.ReconcilerArgs{ + IngressImage: getRequiredEnv("BROKER_INGRESS_IMAGE"), + IngressServiceAccountName: getRequiredEnv("BROKER_INGRESS_SERVICE_ACCOUNT"), + FilterImage: getRequiredEnv("BROKER_FILTER_IMAGE"), + FilterServiceAccountName: getRequiredEnv("BROKER_FILTER_SERVICE_ACCOUNT"), + }), trigger.ProvideController(logger.Desugar()), namespace.ProvideController(logger.Desugar()), } diff --git a/cmd/webhook/main.go b/cmd/webhook/main.go index c82ab87a6dd..a8e0732084a 100644 --- a/cmd/webhook/main.go +++ b/cmd/webhook/main.go @@ -53,19 +53,19 @@ func main() { defer logger.Sync() logger = logger.With(zap.String(logkey.ControllerType, logconfig.Webhook)) - logger.Info("Starting the Eventing Webhook") + logger.Infow("Starting the Eventing Webhook") // set up signals so we handle the first shutdown signal gracefully stopCh := signals.SetupSignalHandler() clusterConfig, err := rest.InClusterConfig() if err != nil { - logger.Fatal("Failed to get in cluster config", zap.Error(err)) + logger.Fatalw("Failed to get in cluster config", zap.Error(err)) } kubeClient, err := kubernetes.NewForConfig(clusterConfig) if err != nil { - logger.Fatal("Failed to get the client set", zap.Error(err)) + logger.Fatalw("Failed to get the client set", zap.Error(err)) } // Watch the logging config map and dynamically update logging levels. @@ -105,8 +105,10 @@ func main() { Logger: logger, } if err != nil { - logger.Fatal("Failed to create the admission controller", zap.Error(err)) + logger.Fatalw("Failed to create the admission controller", zap.Error(err)) } - err = controller.Run(stopCh) - logger.Errorw("Webhook stopping", zap.Error(err)) + if err = controller.Run(stopCh); err != nil { + logger.Errorw("controller.Run() failed", zap.Error(err)) + } + logger.Infow("Webhook stopping") } diff --git a/config/500-controller.yaml b/config/500-controller.yaml index 7dd95d66b36..b09ead19958 100644 --- a/config/500-controller.yaml +++ b/config/500-controller.yaml @@ -39,13 +39,13 @@ spec: valueFrom: fieldRef: fieldPath: metadata.namespace - - name: INGRESS_IMAGE + - name: BROKER_INGRESS_IMAGE value: github.com/knative/eventing/cmd/broker/ingress - - name: INGRESS_SERVICE_ACCOUNT + - name: BROKER_INGRESS_SERVICE_ACCOUNT value: default - - name: FILTER_IMAGE + - name: BROKER_FILTER_IMAGE value: github.com/knative/eventing/cmd/broker/filter - - name: FILTER_SERVICE_ACCOUNT + - name: BROKER_FILTER_SERVICE_ACCOUNT value: eventing-broker-filter volumeMounts: - name: config-logging diff --git a/pkg/apis/eventing/v1alpha1/broker_types.go b/pkg/apis/eventing/v1alpha1/broker_types.go index 6cad4d3efbd..7e0c5a1c9be 100644 --- a/pkg/apis/eventing/v1alpha1/broker_types.go +++ b/pkg/apis/eventing/v1alpha1/broker_types.go @@ -58,6 +58,11 @@ type BrokerSpec struct { // +optional DeprecatedGeneration int64 `json:"generation,omitempty"` + // ChannelTemplate, if specified will be used to create all the Channels used internally by the + // Broker. Only Provisioner and Arguments may be specified. If left unspecified, the default + // Channel for the namespace will be used. + // + // +optional ChannelTemplate *ChannelSpec `json:"channelTemplate,omitempty"` } @@ -90,11 +95,11 @@ type BrokerStatus struct { const ( BrokerConditionReady = duckv1alpha1.ConditionReady - BrokerConditionIngress duckv1alpha1.ConditionType = "Ingress" + BrokerConditionIngress duckv1alpha1.ConditionType = "IngressReady" - BrokerConditionChannel duckv1alpha1.ConditionType = "Channel" + BrokerConditionChannel duckv1alpha1.ConditionType = "ChannelReady" - BrokerConditionFilter duckv1alpha1.ConditionType = "Filter" + BrokerConditionFilter duckv1alpha1.ConditionType = "FilterReady" BrokerConditionAddressable duckv1alpha1.ConditionType = "Addressable" ) @@ -134,8 +139,8 @@ func (bs *BrokerStatus) MarkFilterReady() { brokerCondSet.Manage(bs).MarkTrue(BrokerConditionFilter) } -// SetAddress makes this Channel addressable by setting the hostname. It also -// sets the ChannelConditionAddressable to true. +// SetAddress makes this Broker addressable by setting the hostname. It also +// sets the BrokerConditionAddressable to true. func (bs *BrokerStatus) SetAddress(hostname string) { bs.Address.Hostname = hostname if hostname != "" { diff --git a/pkg/apis/eventing/v1alpha1/broker_types_test.go b/pkg/apis/eventing/v1alpha1/broker_types_test.go index 623a002b642..3970fbcf56a 100644 --- a/pkg/apis/eventing/v1alpha1/broker_types_test.go +++ b/pkg/apis/eventing/v1alpha1/broker_types_test.go @@ -1,5 +1,5 @@ /* -Copyright 2018 The Knative Authors +Copyright 2019 The Knative Authors Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/apis/eventing/v1alpha1/broker_validation.go b/pkg/apis/eventing/v1alpha1/broker_validation.go index 3dbe58255b5..39b495ef31a 100644 --- a/pkg/apis/eventing/v1alpha1/broker_validation.go +++ b/pkg/apis/eventing/v1alpha1/broker_validation.go @@ -25,11 +25,14 @@ func (b *Broker) Validate() *apis.FieldError { } func (bs *BrokerSpec) Validate() *apis.FieldError { - // TODO implement + // TODO validate that the channelTemplate only specifies the provisioner and arguments. return nil } func (b *Broker) CheckImmutableFields(og apis.Immutable) *apis.FieldError { - // TODO implement + // Currently there are no immutable fields. We could make spec.channelTemplate immutable, as + // changing it will normally not have the desired effect of changing the Channel inside the + // Broker. It would have an effect if the existing Channel was then deleted, the newly created + // Channel would use the new spec.channelTemplate. return nil } diff --git a/pkg/apis/eventing/v1alpha1/trigger_defaults.go b/pkg/apis/eventing/v1alpha1/trigger_defaults.go index b95ce930497..2e14b5f28ca 100644 --- a/pkg/apis/eventing/v1alpha1/trigger_defaults.go +++ b/pkg/apis/eventing/v1alpha1/trigger_defaults.go @@ -26,6 +26,18 @@ func (ts *TriggerSpec) SetDefaults() { } // Make a default filter that allows anything. if ts.Filter == nil { - ts.Filter = &TriggerFilter{&TriggerFilterSourceAndType{Type: TriggerAnyFilter, Source: TriggerAnyFilter}} + ts.Filter = &TriggerFilter{} + } + + // Note that this logic will need to change once there are other filtering options, as it should + // only apply if no other filter is applied. + if ts.Filter.SourceAndType == nil { + ts.Filter.SourceAndType = &TriggerFilterSourceAndType{} + } + if ts.Filter.SourceAndType.Type == "" { + ts.Filter.SourceAndType.Type = TriggerAnyFilter + } + if ts.Filter.SourceAndType.Source == "" { + ts.Filter.SourceAndType.Source = TriggerAnyFilter } } diff --git a/pkg/apis/eventing/v1alpha1/trigger_types.go b/pkg/apis/eventing/v1alpha1/trigger_types.go index 794a91b4dc3..89e5b909078 100644 --- a/pkg/apis/eventing/v1alpha1/trigger_types.go +++ b/pkg/apis/eventing/v1alpha1/trigger_types.go @@ -58,11 +58,18 @@ type TriggerSpec struct { // +optional DeprecatedGeneration int64 `json:"generation,omitempty"` + // 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 *SubscriberSpec `json:"subscriber,omitempty"` } @@ -70,6 +77,9 @@ type TriggerFilter struct { SourceAndType *TriggerFilterSourceAndType `json:"sourceAndType,omitempty"` } +// TriggerFilterSourceAndType filters events based on exact matches on the cloud event's type and +// source attributes. Only exact matches will pass the filter. Either or both type and source can +// use the value 'Any' to indicate all strings match. type TriggerFilterSourceAndType struct { Type string `json:"type,omitempty"` Source string `json:"source,omitempty"` @@ -101,9 +111,9 @@ const ( TriggerConditionBrokerExists duckv1alpha1.ConditionType = "BrokerExists" - TriggerConditionKubernetesService duckv1alpha1.ConditionType = "KubernetesService" + TriggerConditionKubernetesService duckv1alpha1.ConditionType = "KubernetesServiceReady" - TriggerConditionVirtualService duckv1alpha1.ConditionType = "VirtualService" + TriggerConditionVirtualService duckv1alpha1.ConditionType = "VirtualServiceReady" TriggerConditionSubscribed duckv1alpha1.ConditionType = "Subscribed" diff --git a/pkg/apis/eventing/v1alpha1/trigger_types_test.go b/pkg/apis/eventing/v1alpha1/trigger_types_test.go index 1d36e8fed7c..3c3c37525d5 100644 --- a/pkg/apis/eventing/v1alpha1/trigger_types_test.go +++ b/pkg/apis/eventing/v1alpha1/trigger_types_test.go @@ -1,5 +1,5 @@ /* -Copyright 2018 The Knative Authors +Copyright 2019 The Knative Authors Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/broker/receiver.go b/pkg/broker/receiver.go index c48c7527056..b591a70ced2 100644 --- a/pkg/broker/receiver.go +++ b/pkg/broker/receiver.go @@ -1,5 +1,5 @@ /* - * Copyright 2018 The Knative Authors + * Copyright 2019 The Knative Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,7 +29,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/manager" ) -// Receiver parses Cloud Events and sends them to a subscriber. +// Receiver parses Cloud Events, determines if they pass a filter, and sends them to a subscriber. type Receiver struct { logger *zap.Logger client client.Client @@ -49,21 +49,20 @@ func New(logger *zap.Logger, client client.Client) (*Receiver, manager.Runnable) } func (r *Receiver) newMessageReceiver() *provisioners.MessageReceiver { - err := r.initClient() - if err != nil { + if err := r.initClient(); err != nil { r.logger.Warn("Failed to initialize client", zap.Error(err)) } return provisioners.NewMessageReceiver(r.sendEvent, r.logger.Sugar()) } // sendEvent sends an event to a subscriber if the trigger filter passes. -func (r *Receiver) sendEvent(channel provisioners.ChannelReference, message *provisioners.Message) error { - r.logger.Debug("received message") +func (r *Receiver) sendEvent(trigger provisioners.ChannelReference, message *provisioners.Message) error { + r.logger.Debug("Received message", zap.Any("triggerRef", trigger)) ctx := context.Background() - t, err := r.getTrigger(ctx, channel) + t, err := r.getTrigger(ctx, trigger) if err != nil { - r.logger.Info("Unable to get the Trigger", zap.Error(err), zap.Any("channelRef", channel)) + r.logger.Info("Unable to get the Trigger", zap.Error(err), zap.Any("triggerRef", trigger)) return err } @@ -74,24 +73,23 @@ func (r *Receiver) sendEvent(channel provisioners.ChannelReference, message *pro } if !r.shouldSendMessage(&t.Spec, message) { - r.logger.Debug("Message did not pass filter") + r.logger.Debug("Message did not pass filter", zap.Any("triggerRef", trigger)) return nil } err = r.dispatcher.DispatchMessage(message, subscriberURI, "", provisioners.DispatchDefaults{}) if err != nil { - r.logger.Info("Failed to dispatch message", zap.Error(err)) + r.logger.Info("Failed to dispatch message", zap.Error(err), zap.Any("triggerRef", trigger)) return err } - r.logger.Debug("Successfully sent message") + r.logger.Debug("Successfully sent message", zap.Any("triggerRef", trigger)) return nil } // Initialize the client. Mainly intended to load stuff in its cache. func (r *Receiver) initClient() error { - // We list triggers so that we can load the client's cache. - // Otherwise, on receiving an event, it may not find the trigger - // and would return an error. + // We list triggers so that we can load the client's cache. Otherwise, on receiving an event, it + // may not find the trigger and would return an error. opts := &client.ListOptions{ // Set Raw because if we need to get more than one page, then we will put the continue token // into opts.Raw.Continue. diff --git a/pkg/broker/receiver_test.go b/pkg/broker/receiver_test.go index d841d895f6b..02a8518a351 100644 --- a/pkg/broker/receiver_test.go +++ b/pkg/broker/receiver_test.go @@ -1,5 +1,5 @@ /* - * Copyright 2018 The Knative Authors + * Copyright 2019 The Knative Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,18 +19,21 @@ package broker import ( "errors" "fmt" - "github.com/knative/eventing/pkg/provisioners" "net/http" "net/http/httptest" "strings" "testing" + "github.com/knative/eventing/pkg/utils" + + "github.com/knative/eventing/pkg/provisioners" + eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" "k8s.io/client-go/kubernetes/scheme" "go.uber.org/zap" - "k8s.io/apimachinery/pkg/apis/meta/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "sigs.k8s.io/controller-runtime/pkg/client/fake" @@ -177,7 +180,7 @@ func makeTriggerWithoutSubscriberURI() *eventingv1alpha1.Trigger { func makeRequest() *http.Request { req := httptest.NewRequest("POST", "/", strings.NewReader(``)) - req.Host = fmt.Sprintf("%s.%s.triggers.cluster.local", triggerName, testNS) + req.Host = fmt.Sprintf("%s.%s.triggers.%s", triggerName, testNS, utils.GetClusterDomainName()) eventAttributes := map[string]string{ "CE-CloudEventsVersion": `"0.1"`, diff --git a/pkg/reconciler/v1alpha1/broker/broker.go b/pkg/reconciler/v1alpha1/broker/broker.go index d72c63cff34..3ad3854589b 100644 --- a/pkg/reconciler/v1alpha1/broker/broker.go +++ b/pkg/reconciler/v1alpha1/broker/broker.go @@ -23,7 +23,6 @@ import ( "k8s.io/apimachinery/pkg/runtime" - "k8s.io/client-go/dynamic" "k8s.io/client-go/rest" "k8s.io/client-go/tools/record" "sigs.k8s.io/controller-runtime/pkg/controller" @@ -67,10 +66,9 @@ const ( ) type reconciler struct { - client client.Client - restConfig *rest.Config - dynamicClient dynamic.Interface - recorder record.EventRecorder + client client.Client + restConfig *rest.Config + recorder record.EventRecorder logger *zap.Logger @@ -83,8 +81,15 @@ type reconciler struct { // Verify the struct implements reconcile.Reconciler. var _ reconcile.Reconciler = &reconciler{} +type ReconcilerArgs struct { + IngressImage string + IngressServiceAccountName string + FilterImage string + FilterServiceAccountName string +} + // ProvideController returns a function that returns a Broker controller. -func ProvideController(logger *zap.Logger, ingressImage, ingressServiceAccount, filterImage, filterServiceAccount string) func(manager.Manager) (controller.Controller, error) { +func ProvideController(logger *zap.Logger, args ReconcilerArgs) func(manager.Manager) (controller.Controller, error) { return func(mgr manager.Manager) (controller.Controller, error) { // Setup a new controller to Reconcile Brokers. c, err := controller.New(controllerAgentName, mgr, controller.Options{ @@ -92,10 +97,10 @@ func ProvideController(logger *zap.Logger, ingressImage, ingressServiceAccount, recorder: mgr.GetRecorder(controllerAgentName), logger: logger, - ingressImage: ingressImage, - ingressServiceAccountName: ingressServiceAccount, - filterImage: filterImage, - filterServiceAccountName: filterServiceAccount, + ingressImage: args.IngressImage, + ingressServiceAccountName: args.IngressServiceAccountName, + filterImage: args.FilterImage, + filterServiceAccountName: args.FilterServiceAccountName, }, }) if err != nil { @@ -124,13 +129,6 @@ func (r *reconciler) InjectClient(c client.Client) error { return nil } -func (r *reconciler) InjectConfig(c *rest.Config) error { - r.restConfig = c - var err error - r.dynamicClient, err = dynamic.NewForConfig(c) - return err -} - // Reconcile compares the actual state with the desired, and attempts to // converge the two. It then updates the Status block of the Broker resource // with the current status of the resource. @@ -139,7 +137,7 @@ func (r *reconciler) Reconcile(request reconcile.Request) (reconcile.Result, err ctx = logging.WithLogger(ctx, r.logger.With(zap.Any("request", request))) broker := &v1alpha1.Broker{} - err := r.client.Get(context.TODO(), request.NamespacedName, broker) + err := r.client.Get(ctx, request.NamespacedName, broker) if errors.IsNotFound(err) { logging.FromContext(ctx).Info("Could not find Broker") @@ -229,10 +227,11 @@ func (r *reconciler) reconcile(ctx context.Context, b *v1alpha1.Broker) (reconci // updateStatus may in fact update the broker's finalizers in addition to the status. func (r *reconciler) updateStatus(broker *v1alpha1.Broker) (*v1alpha1.Broker, error) { + ctx := context.TODO() objectKey := client.ObjectKey{Namespace: broker.Namespace, Name: broker.Name} latestBroker := &v1alpha1.Broker{} - if err := r.client.Get(context.TODO(), objectKey, latestBroker); err != nil { + if err := r.client.Get(ctx, objectKey, latestBroker); err != nil { return nil, err } @@ -240,7 +239,7 @@ func (r *reconciler) updateStatus(broker *v1alpha1.Broker) (*v1alpha1.Broker, er if !equality.Semantic.DeepEqual(latestBroker.Finalizers, broker.Finalizers) { latestBroker.SetFinalizers(broker.ObjectMeta.Finalizers) - if err := r.client.Update(context.TODO(), latestBroker); err != nil { + if err := r.client.Update(ctx, latestBroker); err != nil { return nil, err } brokerChanged = true @@ -253,13 +252,13 @@ func (r *reconciler) updateStatus(broker *v1alpha1.Broker) (*v1alpha1.Broker, er if brokerChanged { // Re-fetch. latestBroker = &v1alpha1.Broker{} - if err := r.client.Get(context.TODO(), objectKey, latestBroker); err != nil { + if err := r.client.Get(ctx, objectKey, latestBroker); err != nil { return nil, err } } latestBroker.Status = broker.Status - if err := r.client.Status().Update(context.TODO(), latestBroker); err != nil { + if err := r.client.Status().Update(ctx, latestBroker); err != nil { return nil, err } @@ -317,14 +316,9 @@ func (r *reconciler) getChannel(ctx context.Context, b *v1alpha1.Broker) (*v1alp opts := &runtimeclient.ListOptions{ Namespace: b.Namespace, LabelSelector: labels.SelectorFromSet(ChannelLabels(b)), - // TODO this is here because the fake client needs it. Remove this when it's no longer - // needed. - Raw: &metav1.ListOptions{ - TypeMeta: metav1.TypeMeta{ - APIVersion: v1alpha1.SchemeGroupVersion.String(), - Kind: "Channel", - }, - }, + // Set Raw because if we need to get more than one page, then we will put the continue token + // into opts.Raw.Continue. + Raw: &metav1.ListOptions{}, } err := r.client.List(ctx, opts, list) @@ -340,7 +334,7 @@ func (r *reconciler) getChannel(ctx context.Context, b *v1alpha1.Broker) (*v1alp return nil, k8serrors.NewNotFound(schema.GroupResource{}, "") } -// newChannel creates a new placeholder Channel object for Broker 'b'. +// newChannel creates a new Channel for Broker 'b'. func newChannel(b *v1alpha1.Broker) *v1alpha1.Channel { var spec v1alpha1.ChannelSpec if b.Spec.ChannelTemplate != nil { diff --git a/pkg/reconciler/v1alpha1/broker/broker_test.go b/pkg/reconciler/v1alpha1/broker/broker_test.go index 992bbe5708e..72de1f15252 100644 --- a/pkg/reconciler/v1alpha1/broker/broker_test.go +++ b/pkg/reconciler/v1alpha1/broker/broker_test.go @@ -20,7 +20,12 @@ import ( "context" "errors" "fmt" - "github.com/google/go-cmp/cmp" + "strings" + "testing" + "time" + + "github.com/knative/eventing/pkg/utils" + "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" controllertesting "github.com/knative/eventing/pkg/reconciler/testing" "github.com/knative/eventing/pkg/reconciler/v1alpha1/broker/resources" @@ -30,21 +35,16 @@ import ( corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" - "k8s.io/client-go/dynamic" "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/rest" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" "sigs.k8s.io/controller-runtime/pkg/reconcile" - "strings" - "testing" - "time" ) const ( - testNS = "test-namespace" - brokerName = "test-broker" - channelHostname = "foo.bar.svc.cluster.local" + testNS = "test-namespace" + brokerName = "test-broker" filterImage = "filter-image" filterSA = "filter-SA" @@ -61,6 +61,8 @@ var ( Name: "my-provisioner", } + channelHostname = fmt.Sprintf("foo.bar.svc.%s", utils.GetClusterDomainName()) + // deletionTime is used when objects are marked as deleted. Rfc3339Copy() // truncates to seconds to match the loss of precision during serialization. deletionTime = metav1.Now().Rfc3339Copy() @@ -107,36 +109,6 @@ func TestInjectClient(t *testing.T) { } } -func TestInjectConfig(t *testing.T) { - r := &reconciler{} - wantCfg := &rest.Config{ - Host: "http://foo", - } - - err := r.InjectConfig(wantCfg) - if err != nil { - t.Fatalf("Unexpected error injecting the config: %v", err) - } - - gotCfg := r.restConfig - if diff := cmp.Diff(wantCfg, gotCfg); diff != "" { - t.Errorf("Unexpected config (-want, +got): %v", diff) - } - - wantDynClient, err := dynamic.NewForConfig(wantCfg) - if err != nil { - t.Fatalf("Unexpected error generating dynamic client: %v", err) - } - - // Since dynamicClient doesn't export any fields, we can only test its type. - switch r.dynamicClient.(type) { - case dynamic.Interface: - // ok - default: - t.Errorf("Unexpected dynamicClient type. Expected: %T, Got: %T", wantDynClient, r.dynamicClient) - } -} - func TestReconcile(t *testing.T) { testCases := []controllertesting.TestCase{ { @@ -578,15 +550,13 @@ func TestReconcile(t *testing.T) { } for _, tc := range testCases { c := tc.GetClient() - dc := tc.GetDynamicClient() recorder := tc.GetEventRecorder() r := &reconciler{ - client: c, - dynamicClient: dc, - restConfig: &rest.Config{}, - recorder: recorder, - logger: zap.NewNop(), + client: c, + restConfig: &rest.Config{}, + recorder: recorder, + logger: zap.NewNop(), filterImage: filterImage, filterServiceAccountName: filterSA, @@ -621,7 +591,7 @@ func makeReadyBroker() *v1alpha1.Broker { b := makeBroker() b.Status.InitializeConditions() b.Status.MarkChannelReady() - b.Status.SetAddress(fmt.Sprintf("%s-broker.%s.svc.cluster.local", brokerName, testNS)) + b.Status.SetAddress(fmt.Sprintf("%s-broker.%s.svc.%s", brokerName, testNS, utils.GetClusterDomainName())) b.Status.MarkFilterReady() b.Status.MarkIngressReady() return b @@ -677,7 +647,7 @@ func makeFilterDeployment() *appsv1.Deployment { }) d.TypeMeta = metav1.TypeMeta{ APIVersion: "apps/v1", - Kind: "Deployment", + Kind: "Deployment", } return d } @@ -692,7 +662,7 @@ func makeFilterService() *corev1.Service { svc := resources.MakeFilterService(makeBroker()) svc.TypeMeta = metav1.TypeMeta{ APIVersion: "v1", - Kind: "Service", + Kind: "Service", } return svc } @@ -712,7 +682,7 @@ func makeIngressDeployment() *appsv1.Deployment { }) d.TypeMeta = metav1.TypeMeta{ APIVersion: "apps/v1", - Kind: "Deployment", + Kind: "Deployment", } return d } @@ -727,7 +697,7 @@ func makeIngressService() *corev1.Service { svc := resources.MakeIngressService(makeBroker()) svc.TypeMeta = metav1.TypeMeta{ APIVersion: "v1", - Kind: "Service", + Kind: "Service", } return svc } diff --git a/pkg/reconciler/v1alpha1/broker/resources/filter.go b/pkg/reconciler/v1alpha1/broker/resources/filter.go index 21c404fae41..f51847c90a8 100644 --- a/pkg/reconciler/v1alpha1/broker/resources/filter.go +++ b/pkg/reconciler/v1alpha1/broker/resources/filter.go @@ -1,5 +1,5 @@ /* -Copyright 2018 The Knative Authors +Copyright 2019 The Knative Authors Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/reconciler/v1alpha1/broker/resources/ingress.go b/pkg/reconciler/v1alpha1/broker/resources/ingress.go index 406f1b85daa..1ebf8957cec 100644 --- a/pkg/reconciler/v1alpha1/broker/resources/ingress.go +++ b/pkg/reconciler/v1alpha1/broker/resources/ingress.go @@ -1,5 +1,5 @@ /* -Copyright 2018 The Knative Authors +Copyright 2019 The Knative Authors Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/reconciler/v1alpha1/namespace/namespace.go b/pkg/reconciler/v1alpha1/namespace/namespace.go index a48cef05c19..a8fd331b4bf 100644 --- a/pkg/reconciler/v1alpha1/namespace/namespace.go +++ b/pkg/reconciler/v1alpha1/namespace/namespace.go @@ -31,7 +31,6 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/dynamic" "k8s.io/client-go/rest" "k8s.io/client-go/tools/record" "sigs.k8s.io/controller-runtime/pkg/client" @@ -47,15 +46,15 @@ const ( // itself when creating events. controllerAgentName = "knative-eventing-namespace-controller" + // Label to enable knative-eventing in a namespace. + knativeEventingLabelKey = "knative-eventing-injection" + knativeEventingLabelValue = "enabled" + defaultBroker = "default" brokerFilterSA = "eventing-broker-filter" brokerFilterRB = "eventing-broker-filter" brokerFilterClusterRole = "eventing-broker-filter" - // Label to enable knative-eventing in a namespace. - knativeEventingLabelKey = "knative-eventing-injection" - knativeEventingLabelValue = "enabled" - // Name of the corev1.Events emitted from the reconciliation process. brokerCreated = "BrokerCreated" serviceAccountCreated = "BrokerFilterServiceAccountCreated" @@ -63,10 +62,9 @@ const ( ) type reconciler struct { - client client.Client - restConfig *rest.Config - dynamicClient dynamic.Interface - recorder record.EventRecorder + client client.Client + restConfig *rest.Config + recorder record.EventRecorder logger *zap.Logger } @@ -126,13 +124,6 @@ func (r *reconciler) InjectClient(c client.Client) error { return nil } -func (r *reconciler) InjectConfig(c *rest.Config) error { - r.restConfig = c - var err error - r.dynamicClient, err = dynamic.NewForConfig(c) - return err -} - // Reconcile compares the actual state with the desired, and attempts to // converge the two. It then updates the Status block of the Namespace resource // with the current status of the resource. @@ -141,7 +132,7 @@ func (r *reconciler) Reconcile(request reconcile.Request) (reconcile.Result, err ctx = logging.WithLogger(ctx, r.logger.With(zap.Any("request", request))) ns := &corev1.Namespace{} - err := r.client.Get(context.TODO(), request.NamespacedName, ns) + err := r.client.Get(ctx, request.NamespacedName, ns) if errors.IsNotFound(err) { logging.FromContext(ctx).Info("Could not find Namespace") @@ -172,6 +163,9 @@ func (r *reconciler) Reconcile(request reconcile.Request) (reconcile.Result, err } func (r *reconciler) reconcile(ctx context.Context, ns *corev1.Namespace) error { + // No need for a finalizer, because everything reconciled is created inside the Namespace. If + // the Namespace is being deleted, then all the reconciled objects will be too. + if ns.DeletionTimestamp != nil { return nil } @@ -305,8 +299,8 @@ func newBrokerFilterRBAC(ns *corev1.Namespace, sa *corev1.ServiceAccount) *rbacv } } -// getBroker returns the default broker for Namespace 'ns' if exists, -// otherwise it returns an error. +// getBroker returns the default broker for Namespace 'ns' if it exists, otherwise it returns an +// error. func (r *reconciler) getBroker(ctx context.Context, ns *corev1.Namespace) (*v1alpha1.Broker, error) { b := &v1alpha1.Broker{} name := types.NamespacedName{ diff --git a/pkg/reconciler/v1alpha1/namespace/namespace_test.go b/pkg/reconciler/v1alpha1/namespace/namespace_test.go index f65c8d85cae..7c1b9e2769c 100644 --- a/pkg/reconciler/v1alpha1/namespace/namespace_test.go +++ b/pkg/reconciler/v1alpha1/namespace/namespace_test.go @@ -30,7 +30,6 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/dynamic" "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/rest" "sigs.k8s.io/controller-runtime/pkg/client" @@ -101,36 +100,6 @@ func TestInjectClient(t *testing.T) { } } -func TestInjectConfig(t *testing.T) { - r := &reconciler{} - wantCfg := &rest.Config{ - Host: "http://foo", - } - - err := r.InjectConfig(wantCfg) - if err != nil { - t.Fatalf("Unexpected error injecting the config: %v", err) - } - - gotCfg := r.restConfig - if diff := cmp.Diff(wantCfg, gotCfg); diff != "" { - t.Errorf("Unexpected config (-want, +got): %v", diff) - } - - wantDynClient, err := dynamic.NewForConfig(wantCfg) - if err != nil { - t.Fatalf("Unexpected error generating dynamic client: %v", err) - } - - // Since dynamicClient doesn't export any fields, we can only test its type. - switch r.dynamicClient.(type) { - case dynamic.Interface: - // ok - default: - t.Errorf("Unexpected dynamicClient type. Expected: %T, Got: %T", wantDynClient, r.dynamicClient) - } -} - func TestNamespaceMapper_Map(t *testing.T) { m := &namespaceMapper{} @@ -269,15 +238,13 @@ func TestReconcile(t *testing.T) { } for _, tc := range testCases { c := tc.GetClient() - dc := tc.GetDynamicClient() recorder := tc.GetEventRecorder() r := &reconciler{ - client: c, - dynamicClient: dc, - restConfig: &rest.Config{}, - recorder: recorder, - logger: zap.NewNop(), + client: c, + restConfig: &rest.Config{}, + recorder: recorder, + logger: zap.NewNop(), } tc.ReconcileKey = fmt.Sprintf("%s/%s", "", testNS) tc.IgnoreTimes = true diff --git a/pkg/reconciler/v1alpha1/trigger/trigger.go b/pkg/reconciler/v1alpha1/trigger/trigger.go index b9e6e8b2341..70529f16740 100644 --- a/pkg/reconciler/v1alpha1/trigger/trigger.go +++ b/pkg/reconciler/v1alpha1/trigger/trigger.go @@ -21,6 +21,8 @@ import ( "fmt" "sync" + "github.com/knative/eventing/pkg/utils" + "github.com/knative/eventing/pkg/provisioners" "k8s.io/apimachinery/pkg/runtime" @@ -131,6 +133,7 @@ func ProvideController(logger *zap.Logger) func(manager.Manager) (controller.Con } } +// mapAllTriggers maps Broker change notifications to Trigger reconcileRequests. type mapAllTriggers struct { r *reconciler } @@ -170,7 +173,7 @@ func (r *reconciler) Reconcile(request reconcile.Request) (reconcile.Result, err ctx = logging.WithLogger(ctx, r.logger.With(zap.Any("request", request))) trigger := &v1alpha1.Trigger{} - err := r.client.Get(context.TODO(), request.NamespacedName, trigger) + err := r.client.Get(ctx, request.NamespacedName, trigger) if errors.IsNotFound(err) { logging.FromContext(ctx).Info("Could not find Trigger") @@ -286,22 +289,15 @@ func (r *reconciler) AddToTriggers(t *v1alpha1.Trigger) { // We will be reconciling an already existing Trigger far more often than adding a new one, so // check with a read lock before using the write lock. r.triggersLock.RLock() - triggersInBrokerNamespacedName := r.triggers[brokerNamespacedName] - var present bool - if triggersInBrokerNamespacedName != nil { - _, present = triggersInBrokerNamespacedName[name] - } else { - present = false - } + _, present := r.triggers[brokerNamespacedName][name] r.triggersLock.RUnlock() - if present { // Already present in the map. return } r.triggersLock.Lock() - triggersInBrokerNamespacedName = r.triggers[brokerNamespacedName] + triggersInBrokerNamespacedName := r.triggers[brokerNamespacedName] if triggersInBrokerNamespacedName == nil { r.triggers[brokerNamespacedName] = make(map[reconcile.Request]struct{}) triggersInBrokerNamespacedName = r.triggers[brokerNamespacedName] @@ -330,12 +326,13 @@ func (r *reconciler) removeFromTriggers(t *v1alpha1.Trigger) { r.triggersLock.Unlock() } -// updateStatus may in fact update the trigger's finalizers in addition to the status +// updateStatus may in fact update the trigger's finalizers in addition to the status. func (r *reconciler) updateStatus(trigger *v1alpha1.Trigger) (*v1alpha1.Trigger, error) { + ctx := context.TODO() objectKey := client.ObjectKey{Namespace: trigger.Namespace, Name: trigger.Name} latestTrigger := &v1alpha1.Trigger{} - if err := r.client.Get(context.TODO(), objectKey, latestTrigger); err != nil { + if err := r.client.Get(ctx, objectKey, latestTrigger); err != nil { return nil, err } @@ -343,7 +340,7 @@ func (r *reconciler) updateStatus(trigger *v1alpha1.Trigger) (*v1alpha1.Trigger, if !equality.Semantic.DeepEqual(latestTrigger.Finalizers, trigger.Finalizers) { latestTrigger.SetFinalizers(trigger.ObjectMeta.Finalizers) - if err := r.client.Update(context.TODO(), latestTrigger); err != nil { + if err := r.client.Update(ctx, latestTrigger); err != nil { return nil, err } triggerChanged = true @@ -356,21 +353,20 @@ func (r *reconciler) updateStatus(trigger *v1alpha1.Trigger) (*v1alpha1.Trigger, if triggerChanged { // Refetch latestTrigger = &v1alpha1.Trigger{} - if err := r.client.Get(context.TODO(), objectKey, latestTrigger); err != nil { + if err := r.client.Get(ctx, objectKey, latestTrigger); err != nil { return nil, err } } latestTrigger.Status = trigger.Status - if err := r.client.Status().Update(context.TODO(), latestTrigger); err != nil { + if err := r.client.Status().Update(ctx, latestTrigger); err != nil { return nil, err } return latestTrigger, nil } -// getBroker returns the Broker for Trigger 't' if exists, -// otherwise it returns an error. +// getBroker returns the Broker for Trigger 't' if exists, otherwise it returns an error. func (r *reconciler) getBroker(ctx context.Context, t *v1alpha1.Trigger) (*v1alpha1.Broker, error) { b := &v1alpha1.Broker{} name := types.NamespacedName{ @@ -381,21 +377,15 @@ func (r *reconciler) getBroker(ctx context.Context, t *v1alpha1.Trigger) (*v1alp return b, err } -// getBrokerChannel returns the Broker's channel if exists, -// otherwise it returns an error. +// getBrokerChannel returns the Broker's channel if exists, otherwise it returns an error. func (r *reconciler) getBrokerChannel(ctx context.Context, b *v1alpha1.Broker) (*v1alpha1.Channel, error) { list := &v1alpha1.ChannelList{} opts := &runtimeclient.ListOptions{ Namespace: b.Namespace, LabelSelector: labels.SelectorFromSet(broker.ChannelLabels(b)), - // TODO this is here because the fake client needs it. Remove this when it's no longer - // needed. - Raw: &metav1.ListOptions{ - TypeMeta: metav1.TypeMeta{ - APIVersion: v1alpha1.SchemeGroupVersion.String(), - Kind: "Channel", - }, - }, + // Set Raw because if we need to get more than one page, then we will put the continue token + // into opts.Raw.Continue. + Raw: &metav1.ListOptions{}, } err := r.client.List(ctx, opts, list) @@ -418,14 +408,9 @@ func (r *reconciler) getK8sService(ctx context.Context, t *v1alpha1.Trigger) (*c opts := &runtimeclient.ListOptions{ Namespace: t.Namespace, LabelSelector: labels.SelectorFromSet(k8sServiceLabels(t)), - // TODO this is here because the fake client needs it. Remove this when it's no longer - // needed. - Raw: &metav1.ListOptions{ - TypeMeta: metav1.TypeMeta{ - APIVersion: corev1.SchemeGroupVersion.String(), - Kind: "Service", - }, - }, + // Set Raw because if we need to get more than one page, then we will put the continue token + // into opts.Raw.Continue. + Raw: &metav1.ListOptions{}, } err := r.client.List(ctx, opts, list) @@ -510,14 +495,9 @@ func (r *reconciler) getVirtualService(ctx context.Context, t *v1alpha1.Trigger) opts := &runtimeclient.ListOptions{ Namespace: t.Namespace, LabelSelector: labels.SelectorFromSet(virtualServiceLabels(t)), - // TODO this is here because the fake client needs it. Remove this when it's no longer - // needed. - Raw: &metav1.ListOptions{ - TypeMeta: metav1.TypeMeta{ - APIVersion: istiov1alpha3.SchemeGroupVersion.String(), - Kind: "VirtualService", - }, - }, + // Set Raw because if we need to get more than one page, then we will put the continue token + // into opts.Raw.Continue. + Raw: &metav1.ListOptions{}, } err := r.client.List(ctx, opts, list) @@ -562,8 +542,7 @@ func (r *reconciler) reconcileVirtualService(ctx context.Context, t *v1alpha1.Tr // newVirtualService returns a placeholder virtual service object for trigger 't' and service 'svc'. func newVirtualService(t *v1alpha1.Trigger, svc *corev1.Service) *istiov1alpha3.VirtualService { - // TODO Make this work with endings other than cluster.local - destinationHost := fmt.Sprintf("%s-broker-filter.%s.svc.cluster.local", t.Spec.Broker, t.Namespace) + destinationHost := fmt.Sprintf("%s-broker-filter.%s.svc.%s", t.Spec.Broker, t.Namespace, utils.GetClusterDomainName()) return &istiov1alpha3.VirtualService{ ObjectMeta: metav1.ObjectMeta{ GenerateName: fmt.Sprintf("%s-", t.Name), @@ -583,8 +562,7 @@ func newVirtualService(t *v1alpha1.Trigger, svc *corev1.Service) *istiov1alpha3. }, Http: []istiov1alpha3.HTTPRoute{{ Rewrite: &istiov1alpha3.HTTPRewrite{ - // Never really used, so cluster.local should be a good enough ending everywhere. - Authority: fmt.Sprintf("%s.%s.triggers.cluster.local", t.Name, t.Namespace), + Authority: fmt.Sprintf("%s.%s.triggers.%s", t.Name, t.Namespace, utils.GetClusterDomainName()), }, Route: []istiov1alpha3.DestinationWeight{{ Destination: istiov1alpha3.Destination{ @@ -651,14 +629,9 @@ func (r *reconciler) getSubscription(ctx context.Context, t *v1alpha1.Trigger) ( opts := &runtimeclient.ListOptions{ Namespace: t.Namespace, LabelSelector: labels.SelectorFromSet(subscriptionLabels(t)), - // TODO this is here because the fake client needs it. Remove this when it's no longer - // needed. - Raw: &metav1.ListOptions{ - TypeMeta: metav1.TypeMeta{ - APIVersion: v1alpha1.SchemeGroupVersion.String(), - Kind: "Subscription", - }, - }, + // Set Raw because if we need to get more than one page, then we will put the continue token + // into opts.Raw.Continue. + Raw: &metav1.ListOptions{}, } err := r.client.List(ctx, opts, list) diff --git a/pkg/reconciler/v1alpha1/trigger/trigger_test.go b/pkg/reconciler/v1alpha1/trigger/trigger_test.go index bb1b8e0336e..229546a684b 100644 --- a/pkg/reconciler/v1alpha1/trigger/trigger_test.go +++ b/pkg/reconciler/v1alpha1/trigger/trigger_test.go @@ -22,6 +22,8 @@ import ( "fmt" "testing" + "github.com/knative/eventing/pkg/utils" + "github.com/knative/eventing/pkg/provisioners" "github.com/knative/eventing/pkg/reconciler/names" @@ -55,9 +57,6 @@ const ( subscriberAPIVersion = "v1" subscriberKind = "Service" subscriberName = "subscriberName" - - channelHostname = "foo.bar.svc.cluster.local" - channelProvisioner = "my-channel-provisioner" ) var ( @@ -498,7 +497,7 @@ func makeReadyTrigger() *v1alpha1.Trigger { provisioners.AddFinalizer(t, finalizerName) t.Status.InitializeConditions() t.Status.MarkBrokerExists() - t.Status.SubscriberURI = fmt.Sprintf("http://%s.%s.svc.cluster.local/", subscriberName, testNS) + t.Status.SubscriberURI = fmt.Sprintf("http://%s.%s.svc.%s/", subscriberName, testNS, utils.GetClusterDomainName()) t.Status.MarkKubernetesServiceExists() t.Status.MarkVirtualServiceExists() t.Status.MarkSubscribed() @@ -555,7 +554,7 @@ func newChannel(name string) *v1alpha1.Channel { }, Status: v1alpha1.ChannelStatus{ Address: duckv1alpha1.Addressable{ - Hostname: channelHostname, + Hostname: "any-non-empty-string", }, }, } From 9819a47e1db6d4c3113cf9566079a5be5a3f9db6 Mon Sep 17 00:00:00 2001 From: nachocano Date: Wed, 27 Feb 2019 14:45:06 -0800 Subject: [PATCH 112/221] Adding namespace to ingress and reconciling service accounts in ns. --- cmd/broker/ingress/main.go | 14 +++- .../v1alpha1/broker/resources/ingress.go | 8 +- .../v1alpha1/namespace/namespace.go | 82 +++++++++++++------ 3 files changed, 75 insertions(+), 29 deletions(-) diff --git a/cmd/broker/ingress/main.go b/cmd/broker/ingress/main.go index c26deaad01a..84f5dac0e2d 100644 --- a/cmd/broker/ingress/main.go +++ b/cmd/broker/ingress/main.go @@ -37,6 +37,12 @@ import ( "sigs.k8s.io/controller-runtime/pkg/manager" ) +const ( + NAMESPACE = "NAMESPACE" + CHANNEL = "CHANNEL" + POLICY = "POLICY" +) + var ( readTimeout = 1 * time.Minute writeTimeout = 1 * time.Minute @@ -50,7 +56,9 @@ func main() { logger.Info("Starting...") - mgr, err := manager.New(config.GetConfigOrDie(), manager.Options{}) + mgr, err := manager.New(config.GetConfigOrDie(), manager.Options{ + Namespace: getRequiredEnv(NAMESPACE), + }) if err != nil { logger.Fatal("Error starting up.", zap.Error(err)) } @@ -61,8 +69,8 @@ func main() { logger.Fatal("Unable to add scheme", zap.Error(err)) } - c := getRequiredEnv("CHANNEL") - policy := getRequiredEnv("POLICY") + c := getRequiredEnv(CHANNEL) + policy := getRequiredEnv(POLICY) h := NewHandler(logger, c, policy, mgr.GetClient()) diff --git a/pkg/reconciler/v1alpha1/broker/resources/ingress.go b/pkg/reconciler/v1alpha1/broker/resources/ingress.go index 4a750390acc..507e2af2ded 100644 --- a/pkg/reconciler/v1alpha1/broker/resources/ingress.go +++ b/pkg/reconciler/v1alpha1/broker/resources/ingress.go @@ -69,8 +69,12 @@ func MakeIngress(args *IngressArgs) *appsv1.Deployment { Name: "ingress", Env: []corev1.EnvVar{ { - Name: "FILTER", - Value: "", // TODO Add one. + Name: "NAMESPACE", + ValueFrom: &corev1.EnvVarSource{ + FieldRef: &corev1.ObjectFieldSelector{ + FieldPath: "metadata.namespace", + }, + }, }, { Name: "CHANNEL", diff --git a/pkg/reconciler/v1alpha1/namespace/namespace.go b/pkg/reconciler/v1alpha1/namespace/namespace.go index a48cef05c19..436a9748439 100644 --- a/pkg/reconciler/v1alpha1/namespace/namespace.go +++ b/pkg/reconciler/v1alpha1/namespace/namespace.go @@ -47,10 +47,13 @@ const ( // itself when creating events. controllerAgentName = "knative-eventing-namespace-controller" - defaultBroker = "default" - brokerFilterSA = "eventing-broker-filter" - brokerFilterRB = "eventing-broker-filter" - brokerFilterClusterRole = "eventing-broker-filter" + defaultBroker = "default" + brokerFilterSA = "eventing-broker-filter" + brokerFilterRB = "eventing-broker-filter" + brokerFilterClusterRole = "eventing-broker-filter" + brokerIngressSA = "eventing-broker-ingress" + brokerIngressRB = "eventing-broker-ingress" + brokerIngressClusterRole = "eventing-broker-ingress" // Label to enable knative-eventing in a namespace. knativeEventingLabelKey = "knative-eventing-injection" @@ -58,8 +61,8 @@ const ( // Name of the corev1.Events emitted from the reconciliation process. brokerCreated = "BrokerCreated" - serviceAccountCreated = "BrokerFilterServiceAccountCreated" - serviceAccountRBACCreated = "BrokerFilterServiceAccountRBACCreated" + serviceAccountCreated = "BrokerServiceAccountCreated" + serviceAccountRBACCreated = "BrokerServiceAccountRBACCreated" ) type reconciler struct { @@ -186,6 +189,17 @@ func (r *reconciler) reconcile(ctx context.Context, ns *corev1.Namespace) error logging.FromContext(ctx).Error("Unable to reconcile the Broker Filter Service Account RBAC for the namespace", zap.Error(err)) return err } + + sa, err = r.reconcileBrokerIngressServiceAccount(ctx, ns) + if err != nil { + logging.FromContext(ctx).Error("Unable to reconcile the Broker Ingress Service Account for the namespace", zap.Error(err)) + return err + } + _, err = r.reconcileBrokerIngressRBAC(ctx, ns, sa) + if err != nil { + logging.FromContext(ctx).Error("Unable to reconcile the Broker Ingress Service Account RBAC for the namespace", zap.Error(err)) + return err + } _, err = r.reconcileBroker(ctx, ns) if err != nil { logging.FromContext(ctx).Error("Unable to reconcile Broker for the namespace", zap.Error(err)) @@ -197,11 +211,21 @@ func (r *reconciler) reconcile(ctx context.Context, ns *corev1.Namespace) error // reconcileBrokerFilterServiceAccount reconciles the Broker's filter service account for Namespace 'ns'. func (r *reconciler) reconcileBrokerFilterServiceAccount(ctx context.Context, ns *corev1.Namespace) (*corev1.ServiceAccount, error) { - current, err := r.getBrokerFilterServiceAccount(ctx, ns) + return r.reconcileBrokerServiceAccount(ctx, ns, brokerFilterSA) +} + +// reconcileBrokerIngressServiceAccount reconciles the Broker's ingress service account for Namespace 'ns'. +func (r *reconciler) reconcileBrokerIngressServiceAccount(ctx context.Context, ns *corev1.Namespace) (*corev1.ServiceAccount, error) { + return r.reconcileBrokerServiceAccount(ctx, ns, brokerIngressSA) +} + +// reconcileBrokerServiceAccount reconciles the Broker's service account called 'serviceAccount' for Namespace 'ns'. +func (r *reconciler) reconcileBrokerServiceAccount(ctx context.Context, ns *corev1.Namespace, serviceAccount string) (*corev1.ServiceAccount, error) { + current, err := r.getBrokerServiceAccount(ctx, ns, serviceAccount) // If the resource doesn't exist, we'll create it. if k8serrors.IsNotFound(err) { - sa := newBrokerFilterServiceAccount(ns) + sa := newBrokerServiceAccount(ns, serviceAccount) err = r.client.Create(ctx, sa) if err != nil { return nil, err @@ -218,24 +242,24 @@ func (r *reconciler) reconcileBrokerFilterServiceAccount(ctx context.Context, ns return current, nil } -// getBrokerFilterServiceAccount returns the Broker's filter service account for Namespace 'ns' if exists, +// getBrokerServiceAccount returns the Broker's service account for Namespace 'ns' called 'serviceAccount' if exists, // otherwise it returns an error. -func (r *reconciler) getBrokerFilterServiceAccount(ctx context.Context, ns *corev1.Namespace) (*corev1.ServiceAccount, error) { +func (r *reconciler) getBrokerServiceAccount(ctx context.Context, ns *corev1.Namespace, serviceAccount string) (*corev1.ServiceAccount, error) { sa := &corev1.ServiceAccount{} name := types.NamespacedName{ Namespace: ns.Name, - Name: brokerFilterSA, + Name: serviceAccount, } err := r.client.Get(ctx, name, sa) return sa, err } -// newBrokerFilterServiceAccount creates a ServiceAccount object for the Namespace 'ns'. -func newBrokerFilterServiceAccount(ns *corev1.Namespace) *corev1.ServiceAccount { +// newBrokerServiceAccount creates a ServiceAccount object for the Namespace 'ns' called 'serviceAccount'. +func newBrokerServiceAccount(ns *corev1.Namespace, serviceAccount string) *corev1.ServiceAccount { return &corev1.ServiceAccount{ ObjectMeta: metav1.ObjectMeta{ Namespace: ns.Name, - Name: brokerFilterSA, + Name: serviceAccount, Labels: injectedLabels(), }, } @@ -249,11 +273,21 @@ func injectedLabels() map[string]string { // reconcileBrokerFilterRBAC reconciles the Broker's filter service account RBAC for the Namespace 'ns'. func (r *reconciler) reconcileBrokerFilterRBAC(ctx context.Context, ns *corev1.Namespace, sa *corev1.ServiceAccount) (*rbacv1.RoleBinding, error) { - current, err := r.getBrokerFilterRBAC(ctx, ns) + return r.reconcileBrokerRBAC(ctx, ns, sa, brokerFilterRB, brokerFilterClusterRole) +} + +// reconcileBrokerIngressRBAC reconciles the Broker's ingress service account RBAC for the Namespace 'ns'. +func (r *reconciler) reconcileBrokerIngressRBAC(ctx context.Context, ns *corev1.Namespace, sa *corev1.ServiceAccount) (*rbacv1.RoleBinding, error) { + return r.reconcileBrokerRBAC(ctx, ns, sa, brokerIngressRB, brokerIngressClusterRole) +} + +// reconcileBrokerRBAC reconciles the Broker's service account RBAC for the RoleBinding 'roleBinding', ClusterRole 'clusterRole', in Namespace 'ns' +func (r *reconciler) reconcileBrokerRBAC(ctx context.Context, ns *corev1.Namespace, sa *corev1.ServiceAccount, roleBinding string, clusterRole string) (*rbacv1.RoleBinding, error) { + current, err := r.getBrokerRBAC(ctx, ns, roleBinding) // If the resource doesn't exist, we'll create it. if k8serrors.IsNotFound(err) { - rbac := newBrokerFilterRBAC(ns, sa) + rbac := newBrokerRBAC(ns, sa, roleBinding, clusterRole) err = r.client.Create(ctx, rbac) if err != nil { return nil, err @@ -261,7 +295,7 @@ func (r *reconciler) reconcileBrokerFilterRBAC(ctx context.Context, ns *corev1.N r.recorder.Event(ns, corev1.EventTypeNormal, serviceAccountRBACCreated, - fmt.Sprintf("Service account RBAC created for the Broker Filter '%s'", rbac.Name)) + fmt.Sprintf("Service account RBAC created for the Broker %s'", rbac.Name)) return rbac, nil } else if err != nil { return nil, err @@ -270,30 +304,30 @@ func (r *reconciler) reconcileBrokerFilterRBAC(ctx context.Context, ns *corev1.N return current, nil } -// getBrokerFilterRBAC returns the Broker's filter role binding for Namespace 'ns' if exists, +// getBrokerRBAC returns the Broker's role binding for Namespace 'ns' called 'roleBinding' if exists, // otherwise it returns an error. -func (r *reconciler) getBrokerFilterRBAC(ctx context.Context, ns *corev1.Namespace) (*rbacv1.RoleBinding, error) { +func (r *reconciler) getBrokerRBAC(ctx context.Context, ns *corev1.Namespace, roleBinding string) (*rbacv1.RoleBinding, error) { rb := &rbacv1.RoleBinding{} name := types.NamespacedName{ Namespace: ns.Name, - Name: brokerFilterRB, + Name: roleBinding, } err := r.client.Get(ctx, name, rb) return rb, err } -// newBrokerFilterRBAC creates a RpleBinding object for the Broker's filter service account 'sa' in the Namespace 'ns'. -func newBrokerFilterRBAC(ns *corev1.Namespace, sa *corev1.ServiceAccount) *rbacv1.RoleBinding { +// newBrokerRBAC creates a RpleBinding object for the Broker's service account 'sa' in the Namespace 'ns' called 'roleBinding', with ClusterRole 'clusterRole'. +func newBrokerRBAC(ns *corev1.Namespace, sa *corev1.ServiceAccount, roleBinding string, clusterRole string) *rbacv1.RoleBinding { return &rbacv1.RoleBinding{ ObjectMeta: metav1.ObjectMeta{ Namespace: ns.Name, - Name: brokerFilterRB, + Name: roleBinding, Labels: injectedLabels(), }, RoleRef: rbacv1.RoleRef{ APIGroup: "rbac.authorization.k8s.io", Kind: "ClusterRole", - Name: brokerFilterClusterRole, + Name: clusterRole, }, Subjects: []rbacv1.Subject{ { From 930261e6d782fa1f5721f10c21830aaec2501461 Mon Sep 17 00:00:00 2001 From: nachocano Date: Wed, 27 Feb 2019 14:59:45 -0800 Subject: [PATCH 113/221] More changes --- config/200-broker-clusterrole.yaml | 17 +++++++++++++ config/200-eventtype-clusterrole.yaml | 28 --------------------- config/201-eventype-clusterrolebinding.yaml | 26 ------------------- config/500-controller.yaml | 2 +- 4 files changed, 18 insertions(+), 55 deletions(-) delete mode 100644 config/200-eventtype-clusterrole.yaml delete mode 100644 config/201-eventype-clusterrolebinding.yaml diff --git a/config/200-broker-clusterrole.yaml b/config/200-broker-clusterrole.yaml index fc430c0dc8f..b1006375862 100644 --- a/config/200-broker-clusterrole.yaml +++ b/config/200-broker-clusterrole.yaml @@ -26,3 +26,20 @@ rules: - get - list - watch + +--- + +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: eventing-broker-ingress +rules: + - apiGroups: + - eventing.knative.dev + resources: + - event-types + - event-types/status + verbs: + - get + - list + - watch diff --git a/config/200-eventtype-clusterrole.yaml b/config/200-eventtype-clusterrole.yaml deleted file mode 100644 index 395ba8aa54d..00000000000 --- a/config/200-eventtype-clusterrole.yaml +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright 2019 The Knative Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: eventing-event-type -rules: - - apiGroups: - - eventing.knative.dev - resources: - - event-types - - event-types/status - verbs: - - get - - list - - watch diff --git a/config/201-eventype-clusterrolebinding.yaml b/config/201-eventype-clusterrolebinding.yaml deleted file mode 100644 index 1425fa03975..00000000000 --- a/config/201-eventype-clusterrolebinding.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright 2018 The Knative Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: eventing-ingress-eventtype -subjects: - - kind: ServiceAccount - name: default - namespace: default -roleRef: - kind: ClusterRole - name: eventing-event-type - apiGroup: rbac.authorization.k8s.io - diff --git a/config/500-controller.yaml b/config/500-controller.yaml index e77c1bcfda7..2577eab5158 100644 --- a/config/500-controller.yaml +++ b/config/500-controller.yaml @@ -42,7 +42,7 @@ spec: - name: INGRESS_IMAGE value: github.com/knative/eventing/cmd/broker/ingress - name: INGRESS_SERVICE_ACCOUNT - value: default + value: eventing-broker-ingress - name: INGRESS_POLICY value: allow_registered_types - name: FILTER_IMAGE From f6af7078c3776c60be1f4048a2b119d05dbb2fb0 Mon Sep 17 00:00:00 2001 From: nachocano Date: Wed, 27 Feb 2019 15:40:58 -0800 Subject: [PATCH 114/221] Service account in namespace --- config/500-controller.yaml | 4 +- .../v1alpha1/namespace/namespace.go | 99 +++++++++++++------ 2 files changed, 70 insertions(+), 33 deletions(-) diff --git a/config/500-controller.yaml b/config/500-controller.yaml index 4b7276b6d2d..8f5a9e85240 100644 --- a/config/500-controller.yaml +++ b/config/500-controller.yaml @@ -42,9 +42,9 @@ spec: - name: BROKER_INGRESS_IMAGE value: github.com/knative/eventing/cmd/broker/ingress - name: BROKER_INGRESS_SERVICE_ACCOUNT - value: default + value: eventing-broker-ingress - name: BROKER_INGRESS_POLICY - value: allow_registered_types + value: allow_any - name: BROKER_FILTER_IMAGE value: github.com/knative/eventing/cmd/broker/filter - name: BROKER_FILTER_SERVICE_ACCOUNT diff --git a/pkg/reconciler/v1alpha1/namespace/namespace.go b/pkg/reconciler/v1alpha1/namespace/namespace.go index a8fd331b4bf..4259e4ec50c 100644 --- a/pkg/reconciler/v1alpha1/namespace/namespace.go +++ b/pkg/reconciler/v1alpha1/namespace/namespace.go @@ -50,15 +50,20 @@ const ( knativeEventingLabelKey = "knative-eventing-injection" knativeEventingLabelValue = "enabled" - defaultBroker = "default" - brokerFilterSA = "eventing-broker-filter" - brokerFilterRB = "eventing-broker-filter" - brokerFilterClusterRole = "eventing-broker-filter" + defaultBroker = "default" + brokerFilterSA = "eventing-broker-filter" + brokerFilterRB = "eventing-broker-filter" + brokerFilterClusterRole = "eventing-broker-filter" + brokerIngressSA = "eventing-broker-ingress" + brokerIngressRB = "eventing-broker-ingress" + brokerIngressClusterRole = "eventing-broker-ingress" // Name of the corev1.Events emitted from the reconciliation process. - brokerCreated = "BrokerCreated" - serviceAccountCreated = "BrokerFilterServiceAccountCreated" - serviceAccountRBACCreated = "BrokerFilterServiceAccountRBACCreated" + brokerCreated = "BrokerCreated" + filterServiceAccountCreated = "BrokerFilterServiceAccountCreated" + filterServiceAccountRBACCreated = "BrokerFilterServiceAccountRBACCreated" + ingressServiceAccountCreated = "BrokerIngressServiceAccountCreated" + ingressServiceAccountRBACCreated = "BrokerIngressServiceAccountRBACCreated" ) type reconciler struct { @@ -180,6 +185,17 @@ func (r *reconciler) reconcile(ctx context.Context, ns *corev1.Namespace) error logging.FromContext(ctx).Error("Unable to reconcile the Broker Filter Service Account RBAC for the namespace", zap.Error(err)) return err } + + sa, err = r.reconcileBrokerIngressServiceAccount(ctx, ns) + if err != nil { + logging.FromContext(ctx).Error("Unable to reconcile the Broker Ingress Service Account for the namespace", zap.Error(err)) + return err + } + _, err = r.reconcileBrokerIngressRBAC(ctx, ns, sa) + if err != nil { + logging.FromContext(ctx).Error("Unable to reconcile the Broker Ingress Service Account RBAC for the namespace", zap.Error(err)) + return err + } _, err = r.reconcileBroker(ctx, ns) if err != nil { logging.FromContext(ctx).Error("Unable to reconcile Broker for the namespace", zap.Error(err)) @@ -191,19 +207,29 @@ func (r *reconciler) reconcile(ctx context.Context, ns *corev1.Namespace) error // reconcileBrokerFilterServiceAccount reconciles the Broker's filter service account for Namespace 'ns'. func (r *reconciler) reconcileBrokerFilterServiceAccount(ctx context.Context, ns *corev1.Namespace) (*corev1.ServiceAccount, error) { - current, err := r.getBrokerFilterServiceAccount(ctx, ns) + return r.reconcileBrokerServiceAccount(ctx, ns, brokerFilterSA, filterServiceAccountCreated) +} + +// reconcileBrokerIngressServiceAccount reconciles the Broker's ingress service account for Namespace 'ns'. +func (r *reconciler) reconcileBrokerIngressServiceAccount(ctx context.Context, ns *corev1.Namespace) (*corev1.ServiceAccount, error) { + return r.reconcileBrokerServiceAccount(ctx, ns, brokerIngressSA, ingressServiceAccountCreated) +} + +// reconcileBrokerServiceAccount reconciles the Broker's service account called 'serviceAccount' for Namespace 'ns'. +func (r *reconciler) reconcileBrokerServiceAccount(ctx context.Context, ns *corev1.Namespace, serviceAccount string, eventName string) (*corev1.ServiceAccount, error) { + current, err := r.getBrokerServiceAccount(ctx, ns, serviceAccount) // If the resource doesn't exist, we'll create it. if k8serrors.IsNotFound(err) { - sa := newBrokerFilterServiceAccount(ns) + sa := newBrokerServiceAccount(ns, serviceAccount) err = r.client.Create(ctx, sa) if err != nil { return nil, err } r.recorder.Event(ns, corev1.EventTypeNormal, - serviceAccountCreated, - fmt.Sprintf("Service account created for the Broker '%s'", sa.Name)) + eventName, + fmt.Sprintf("Service account created for the Broker %q", sa.Name)) return sa, nil } else if err != nil { return nil, err @@ -212,24 +238,24 @@ func (r *reconciler) reconcileBrokerFilterServiceAccount(ctx context.Context, ns return current, nil } -// getBrokerFilterServiceAccount returns the Broker's filter service account for Namespace 'ns' if exists, +// getBrokerServiceAccount returns the Broker's service account for Namespace 'ns' called 'serviceAccount' if it exists, // otherwise it returns an error. -func (r *reconciler) getBrokerFilterServiceAccount(ctx context.Context, ns *corev1.Namespace) (*corev1.ServiceAccount, error) { +func (r *reconciler) getBrokerServiceAccount(ctx context.Context, ns *corev1.Namespace, serviceAccount string) (*corev1.ServiceAccount, error) { sa := &corev1.ServiceAccount{} name := types.NamespacedName{ Namespace: ns.Name, - Name: brokerFilterSA, + Name: serviceAccount, } err := r.client.Get(ctx, name, sa) return sa, err } -// newBrokerFilterServiceAccount creates a ServiceAccount object for the Namespace 'ns'. -func newBrokerFilterServiceAccount(ns *corev1.Namespace) *corev1.ServiceAccount { +// newBrokerServiceAccount creates a ServiceAccount object for the Namespace 'ns' called 'serviceAccount'. +func newBrokerServiceAccount(ns *corev1.Namespace, serviceAccount string) *corev1.ServiceAccount { return &corev1.ServiceAccount{ ObjectMeta: metav1.ObjectMeta{ Namespace: ns.Name, - Name: brokerFilterSA, + Name: serviceAccount, Labels: injectedLabels(), }, } @@ -243,19 +269,30 @@ func injectedLabels() map[string]string { // reconcileBrokerFilterRBAC reconciles the Broker's filter service account RBAC for the Namespace 'ns'. func (r *reconciler) reconcileBrokerFilterRBAC(ctx context.Context, ns *corev1.Namespace, sa *corev1.ServiceAccount) (*rbacv1.RoleBinding, error) { - current, err := r.getBrokerFilterRBAC(ctx, ns) + return r.reconcileBrokerRBAC(ctx, ns, sa, brokerFilterRB, brokerFilterClusterRole, filterServiceAccountRBACCreated) +} + +// reconcileBrokerIngressRBAC reconciles the Broker's ingress service account RBAC for the Namespace 'ns'. +func (r *reconciler) reconcileBrokerIngressRBAC(ctx context.Context, ns *corev1.Namespace, sa *corev1.ServiceAccount) (*rbacv1.RoleBinding, error) { + return r.reconcileBrokerRBAC(ctx, ns, sa, brokerIngressRB, brokerIngressClusterRole, ingressServiceAccountRBACCreated) +} + +// reconcileBrokerRBAC reconciles the Broker's service account RBAC for the RoleBinding 'roleBinding', ClusterRole +// 'clusterRole', in Namespace 'ns'. +func (r *reconciler) reconcileBrokerRBAC(ctx context.Context, ns *corev1.Namespace, sa *corev1.ServiceAccount, roleBinding, clusterRole, eventName string) (*rbacv1.RoleBinding, error) { + current, err := r.getBrokerRBAC(ctx, ns, roleBinding) // If the resource doesn't exist, we'll create it. if k8serrors.IsNotFound(err) { - rbac := newBrokerFilterRBAC(ns, sa) + rbac := newBrokerRBAC(ns, sa, roleBinding, clusterRole) err = r.client.Create(ctx, rbac) if err != nil { return nil, err } r.recorder.Event(ns, corev1.EventTypeNormal, - serviceAccountRBACCreated, - fmt.Sprintf("Service account RBAC created for the Broker Filter '%s'", rbac.Name)) + eventName, + fmt.Sprintf("Service account RBAC created for the Broker %q", rbac.Name)) return rbac, nil } else if err != nil { return nil, err @@ -264,30 +301,31 @@ func (r *reconciler) reconcileBrokerFilterRBAC(ctx context.Context, ns *corev1.N return current, nil } -// getBrokerFilterRBAC returns the Broker's filter role binding for Namespace 'ns' if exists, -// otherwise it returns an error. -func (r *reconciler) getBrokerFilterRBAC(ctx context.Context, ns *corev1.Namespace) (*rbacv1.RoleBinding, error) { +// getBrokerRBAC returns the Broker's role binding for Namespace 'ns' called 'roleBinding' if it exists, otherwise it +// returns an error. +func (r *reconciler) getBrokerRBAC(ctx context.Context, ns *corev1.Namespace, roleBinding string) (*rbacv1.RoleBinding, error) { rb := &rbacv1.RoleBinding{} name := types.NamespacedName{ Namespace: ns.Name, - Name: brokerFilterRB, + Name: roleBinding, } err := r.client.Get(ctx, name, rb) return rb, err } -// newBrokerFilterRBAC creates a RpleBinding object for the Broker's filter service account 'sa' in the Namespace 'ns'. -func newBrokerFilterRBAC(ns *corev1.Namespace, sa *corev1.ServiceAccount) *rbacv1.RoleBinding { +// newBrokerRBAC creates a RpleBinding object for the Broker's service account 'sa' in the Namespace 'ns' called +// 'roleBinding', with ClusterRole 'clusterRole'. +func newBrokerRBAC(ns *corev1.Namespace, sa *corev1.ServiceAccount, roleBinding string, clusterRole string) *rbacv1.RoleBinding { return &rbacv1.RoleBinding{ ObjectMeta: metav1.ObjectMeta{ Namespace: ns.Name, - Name: brokerFilterRB, + Name: roleBinding, Labels: injectedLabels(), }, RoleRef: rbacv1.RoleRef{ APIGroup: "rbac.authorization.k8s.io", Kind: "ClusterRole", - Name: brokerFilterClusterRole, + Name: clusterRole, }, Subjects: []rbacv1.Subject{ { @@ -299,8 +337,7 @@ func newBrokerFilterRBAC(ns *corev1.Namespace, sa *corev1.ServiceAccount) *rbacv } } -// getBroker returns the default broker for Namespace 'ns' if it exists, otherwise it returns an -// error. +// getBroker returns the default broker for Namespace 'ns' if it exists, otherwise it returns an error. func (r *reconciler) getBroker(ctx context.Context, ns *corev1.Namespace) (*v1alpha1.Broker, error) { b := &v1alpha1.Broker{} name := types.NamespacedName{ From 026bc20b8999979d0fa6fc4b8c94ecfac4970a04 Mon Sep 17 00:00:00 2001 From: nachocano Date: Wed, 27 Feb 2019 15:53:39 -0800 Subject: [PATCH 115/221] Updating events registered --- config/500-controller.yaml | 2 +- pkg/broker/ingress.go | 17 +++++++---------- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/config/500-controller.yaml b/config/500-controller.yaml index 8f5a9e85240..58f780057ec 100644 --- a/config/500-controller.yaml +++ b/config/500-controller.yaml @@ -44,7 +44,7 @@ spec: - name: BROKER_INGRESS_SERVICE_ACCOUNT value: eventing-broker-ingress - name: BROKER_INGRESS_POLICY - value: allow_any + value: allow_registered - name: BROKER_FILTER_IMAGE value: github.com/knative/eventing/cmd/broker/filter - name: BROKER_FILTER_SERVICE_ACCOUNT diff --git a/pkg/broker/ingress.go b/pkg/broker/ingress.go index 0aef1fdc3c3..bddd358caaf 100644 --- a/pkg/broker/ingress.go +++ b/pkg/broker/ingress.go @@ -29,7 +29,7 @@ import ( const ( allowAny = "allow_any" - allowRegisteredTypes = "allow_registered_types" + allowRegisteredTypes = "allow_registered" ) type IngressPolicy interface { @@ -38,7 +38,7 @@ type IngressPolicy interface { type AllowAnyPolicy struct{} -type AllowRegisteredTypesPolicy struct { +type AllowRegisteredPolicy struct { logger *zap.SugaredLogger client client.Client } @@ -50,7 +50,7 @@ func NewIngressPolicy(logger *zap.SugaredLogger, client client.Client, policy st func newIngressPolicy(logger *zap.SugaredLogger, client client.Client, policy string) IngressPolicy { switch policy { case allowRegisteredTypes: - return &AllowRegisteredTypesPolicy{ + return &AllowRegisteredPolicy{ logger: logger, client: client, } @@ -65,7 +65,7 @@ func (policy *AllowAnyPolicy) AllowMessage(namespace string, message *provisione return true } -func (policy *AllowRegisteredTypesPolicy) AllowMessage(namespace string, message *provisioners.Message) bool { +func (policy *AllowRegisteredPolicy) AllowMessage(namespace string, message *provisioners.Message) bool { eventType := &eventingv1alpha1.EventType{} name := message.Headers["Ce-Eventtype"] @@ -77,12 +77,9 @@ func (policy *AllowRegisteredTypesPolicy) AllowMessage(namespace string, message eventType) if k8serrors.IsNotFound(err) { - policy.logger.Error("EventType not found", zap.String("type", name)) - return false + policy.logger.Warnf("EventType not found %s", name) } else if err != nil { - policy.logger.Error("Error getting EventType", zap.String("type", name)) - return false - } else { - return true + policy.logger.Errorf("Error getting EventType %s", name) } + return err != nil } From c11a60fc0f279b1d1fb14ab8dad66edb91917b0c Mon Sep 17 00:00:00 2001 From: nachocano Date: Wed, 27 Feb 2019 16:12:17 -0800 Subject: [PATCH 116/221] Updating origin to source. --- config/300-eventtype.yaml | 4 +- e.yaml | 2 +- pkg/apis/eventing/v1alpha1/eventtype_types.go | 3 +- .../eventing/v1alpha1/eventtype_validation.go | 2 +- pkg/broker/ingress.go | 8 +- .../typed/eventing/v1alpha1/eventtype.go | 174 ++++++++++++++++++ .../eventing/v1alpha1/fake/fake_eventtype.go | 140 ++++++++++++++ .../eventing/v1alpha1/eventtype.go | 89 +++++++++ .../listers/eventing/v1alpha1/eventtype.go | 94 ++++++++++ 9 files changed, 508 insertions(+), 8 deletions(-) create mode 100644 pkg/client/clientset/versioned/typed/eventing/v1alpha1/eventtype.go create mode 100644 pkg/client/clientset/versioned/typed/eventing/v1alpha1/fake/fake_eventtype.go create mode 100644 pkg/client/informers/externalversions/eventing/v1alpha1/eventtype.go create mode 100644 pkg/client/listers/eventing/v1alpha1/eventtype.go diff --git a/config/300-eventtype.yaml b/config/300-eventtype.yaml index 682e84e943a..b49cc7ea5a1 100644 --- a/config/300-eventtype.yaml +++ b/config/300-eventtype.yaml @@ -30,9 +30,9 @@ spec: subresources: status: {} additionalPrinterColumns: - - name: Origin + - name: Source type: string - JSONPath: ".spec.origin" + JSONPath: ".spec.source" - name: Schema type: string JSONPath: ".spec.schema" diff --git a/e.yaml b/e.yaml index 43a7cd8c5ef..66efcaf7634 100644 --- a/e.yaml +++ b/e.yaml @@ -3,6 +3,6 @@ kind: EventType metadata: name: com.github.pullrequest spec: - origin: github.com + source: github.com schema: http://foo2.example/schema diff --git a/pkg/apis/eventing/v1alpha1/eventtype_types.go b/pkg/apis/eventing/v1alpha1/eventtype_types.go index 2cc0f0fe343..bb9b77ed972 100644 --- a/pkg/apis/eventing/v1alpha1/eventtype_types.go +++ b/pkg/apis/eventing/v1alpha1/eventtype_types.go @@ -58,7 +58,8 @@ type EventTypeSpec struct { // +optional DeprecatedGeneration int64 `json:"generation,omitempty"` - Origin string `json:"origin,omitempty"` + // TODO this should probably need to be updated + Source string `json:"source,omitempty"` // +optional Schema string `json:"schema,omitempty"` } diff --git a/pkg/apis/eventing/v1alpha1/eventtype_validation.go b/pkg/apis/eventing/v1alpha1/eventtype_validation.go index b7b9a82502d..d22f771baa6 100644 --- a/pkg/apis/eventing/v1alpha1/eventtype_validation.go +++ b/pkg/apis/eventing/v1alpha1/eventtype_validation.go @@ -41,7 +41,7 @@ func (r *EventType) CheckImmutableFields(og apis.Immutable) *apis.FieldError { } // TODO check other fields. - if diff := cmp.Diff(original.Spec.Origin, r.Spec.Origin); diff != "" { + if diff := cmp.Diff(original.Spec.Source, r.Spec.Source); diff != "" { return &apis.FieldError{ Message: "Immutable fields changed (-old +new)", Paths: []string{"spec", "events"}, diff --git a/pkg/broker/ingress.go b/pkg/broker/ingress.go index bddd358caaf..aac40d506e9 100644 --- a/pkg/broker/ingress.go +++ b/pkg/broker/ingress.go @@ -77,9 +77,11 @@ func (policy *AllowRegisteredPolicy) AllowMessage(namespace string, message *pro eventType) if k8serrors.IsNotFound(err) { - policy.logger.Warnf("EventType not found %s", name) + policy.logger.Warnf("EventType not found: %q", name) + return false } else if err != nil { - policy.logger.Errorf("Error getting EventType %s", name) + policy.logger.Errorf("Error getting EventType: %q, %v", name, err) + return false } - return err != nil + return true } diff --git a/pkg/client/clientset/versioned/typed/eventing/v1alpha1/eventtype.go b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/eventtype.go new file mode 100644 index 00000000000..55c445c67ce --- /dev/null +++ b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/eventtype.go @@ -0,0 +1,174 @@ +/* +Copyright 2018 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + v1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" + scheme "github.com/knative/eventing/pkg/client/clientset/versioned/scheme" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" +) + +// 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(*v1alpha1.EventType) (*v1alpha1.EventType, error) + Update(*v1alpha1.EventType) (*v1alpha1.EventType, error) + UpdateStatus(*v1alpha1.EventType) (*v1alpha1.EventType, error) + Delete(name string, options *v1.DeleteOptions) error + DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error + Get(name string, options v1.GetOptions) (*v1alpha1.EventType, error) + List(opts v1.ListOptions) (*v1alpha1.EventTypeList, error) + Watch(opts v1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.EventType, err error) + EventTypeExpansion +} + +// eventTypes implements EventTypeInterface +type eventTypes struct { + client rest.Interface + ns string +} + +// newEventTypes returns a EventTypes +func newEventTypes(c *EventingV1alpha1Client, 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 v1.GetOptions) (result *v1alpha1.EventType, err error) { + result = &v1alpha1.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 v1.ListOptions) (result *v1alpha1.EventTypeList, err error) { + result = &v1alpha1.EventTypeList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("eventtypes"). + VersionedParams(&opts, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested eventTypes. +func (c *eventTypes) Watch(opts v1.ListOptions) (watch.Interface, error) { + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("eventtypes"). + VersionedParams(&opts, scheme.ParameterCodec). + 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 *v1alpha1.EventType) (result *v1alpha1.EventType, err error) { + result = &v1alpha1.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 *v1alpha1.EventType) (result *v1alpha1.EventType, err error) { + result = &v1alpha1.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 *v1alpha1.EventType) (result *v1alpha1.EventType, err error) { + result = &v1alpha1.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 *v1.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 *v1.DeleteOptions, listOptions v1.ListOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("eventtypes"). + VersionedParams(&listOptions, scheme.ParameterCodec). + 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 *v1alpha1.EventType, err error) { + result = &v1alpha1.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/v1alpha1/fake/fake_eventtype.go b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/fake/fake_eventtype.go new file mode 100644 index 00000000000..592074ffad5 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/fake/fake_eventtype.go @@ -0,0 +1,140 @@ +/* +Copyright 2018 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT 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 ( + v1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" + 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" +) + +// FakeEventTypes implements EventTypeInterface +type FakeEventTypes struct { + Fake *FakeEventingV1alpha1 + ns string +} + +var eventtypesResource = schema.GroupVersionResource{Group: "eventing.knative.dev", Version: "v1alpha1", Resource: "eventtypes"} + +var eventtypesKind = schema.GroupVersionKind{Group: "eventing.knative.dev", Version: "v1alpha1", 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 *v1alpha1.EventType, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(eventtypesResource, c.ns, name), &v1alpha1.EventType{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.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 *v1alpha1.EventTypeList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(eventtypesResource, eventtypesKind, c.ns, opts), &v1alpha1.EventTypeList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.EventTypeList{ListMeta: obj.(*v1alpha1.EventTypeList).ListMeta} + for _, item := range obj.(*v1alpha1.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 *v1alpha1.EventType) (result *v1alpha1.EventType, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(eventtypesResource, c.ns, eventType), &v1alpha1.EventType{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.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 *v1alpha1.EventType) (result *v1alpha1.EventType, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(eventtypesResource, c.ns, eventType), &v1alpha1.EventType{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.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 *v1alpha1.EventType) (*v1alpha1.EventType, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(eventtypesResource, "status", c.ns, eventType), &v1alpha1.EventType{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.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), &v1alpha1.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, &v1alpha1.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 *v1alpha1.EventType, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(eventtypesResource, c.ns, name, data, subresources...), &v1alpha1.EventType{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.EventType), err +} diff --git a/pkg/client/informers/externalversions/eventing/v1alpha1/eventtype.go b/pkg/client/informers/externalversions/eventing/v1alpha1/eventtype.go new file mode 100644 index 00000000000..9e62ba5e723 --- /dev/null +++ b/pkg/client/informers/externalversions/eventing/v1alpha1/eventtype.go @@ -0,0 +1,89 @@ +/* +Copyright 2018 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + time "time" + + eventing_v1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" + versioned "github.com/knative/eventing/pkg/client/clientset/versioned" + internalinterfaces "github.com/knative/eventing/pkg/client/informers/externalversions/internalinterfaces" + v1alpha1 "github.com/knative/eventing/pkg/client/listers/eventing/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" +) + +// EventTypeInformer provides access to a shared informer and lister for +// EventTypes. +type EventTypeInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1alpha1.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 v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.EventingV1alpha1().EventTypes(namespace).List(options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.EventingV1alpha1().EventTypes(namespace).Watch(options) + }, + }, + &eventing_v1alpha1.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(&eventing_v1alpha1.EventType{}, f.defaultInformer) +} + +func (f *eventTypeInformer) Lister() v1alpha1.EventTypeLister { + return v1alpha1.NewEventTypeLister(f.Informer().GetIndexer()) +} diff --git a/pkg/client/listers/eventing/v1alpha1/eventtype.go b/pkg/client/listers/eventing/v1alpha1/eventtype.go new file mode 100644 index 00000000000..ffbdf6afdd5 --- /dev/null +++ b/pkg/client/listers/eventing/v1alpha1/eventtype.go @@ -0,0 +1,94 @@ +/* +Copyright 2018 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + v1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" +) + +// EventTypeLister helps list EventTypes. +type EventTypeLister interface { + // List lists all EventTypes in the indexer. + List(selector labels.Selector) (ret []*v1alpha1.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 []*v1alpha1.EventType, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.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 []*v1alpha1.EventType, err error) + // Get retrieves the EventType from the indexer for a given namespace and name. + Get(name string) (*v1alpha1.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 []*v1alpha1.EventType, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.EventType)) + }) + return ret, err +} + +// Get retrieves the EventType from the indexer for a given namespace and name. +func (s eventTypeNamespaceLister) Get(name string) (*v1alpha1.EventType, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1alpha1.Resource("eventtype"), name) + } + return obj.(*v1alpha1.EventType), nil +} From ee3ac4ccf1b7769e375a9efd63b6ce0754eef5cf Mon Sep 17 00:00:00 2001 From: nachocano Date: Wed, 27 Feb 2019 16:17:16 -0800 Subject: [PATCH 117/221] to newer version --- b.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/b.yaml b/b.yaml index 54ad31cbd23..eaab24a62b5 100644 --- a/b.yaml +++ b/b.yaml @@ -7,5 +7,5 @@ spec: provisioner: apiVersion: eventing.knative.dev/v1alpha1 kind: ClusterChannelProvisioner - name: in-memory-channel + name: in-memory From 796711b959c146fdf2019c1aba3697290eb58f4b Mon Sep 17 00:00:00 2001 From: nachocano Date: Wed, 27 Feb 2019 17:05:06 -0800 Subject: [PATCH 118/221] moving the ingress policy to the broker itself... should be an object instead of a string. --- b3.yaml | 6 ++++++ cmd/controller/main.go | 1 - config/500-controller.yaml | 2 -- pkg/apis/eventing/v1alpha1/broker_types.go | 4 ++++ pkg/reconciler/v1alpha1/broker/broker.go | 4 ---- pkg/reconciler/v1alpha1/broker/resources/ingress.go | 3 +-- 6 files changed, 11 insertions(+), 9 deletions(-) create mode 100644 b3.yaml diff --git a/b3.yaml b/b3.yaml new file mode 100644 index 00000000000..1bd3e2af6f7 --- /dev/null +++ b/b3.yaml @@ -0,0 +1,6 @@ +apiVersion: eventing.knative.dev/v1alpha1 +kind: Broker +metadata: + name: broker-test +spec: + ingressPolicy: allow_registered diff --git a/cmd/controller/main.go b/cmd/controller/main.go index 6b3a15a01e9..60c46d4d967 100644 --- a/cmd/controller/main.go +++ b/cmd/controller/main.go @@ -127,7 +127,6 @@ func main() { broker.ReconcilerArgs{ IngressImage: getRequiredEnv("BROKER_INGRESS_IMAGE"), IngressServiceAccountName: getRequiredEnv("BROKER_INGRESS_SERVICE_ACCOUNT"), - IngressPolicy: getRequiredEnv("BROKER_INGRESS_POLICY"), FilterImage: getRequiredEnv("BROKER_FILTER_IMAGE"), FilterServiceAccountName: getRequiredEnv("BROKER_FILTER_SERVICE_ACCOUNT"), }), diff --git a/config/500-controller.yaml b/config/500-controller.yaml index 58f780057ec..c52351d8cb0 100644 --- a/config/500-controller.yaml +++ b/config/500-controller.yaml @@ -43,8 +43,6 @@ spec: value: github.com/knative/eventing/cmd/broker/ingress - name: BROKER_INGRESS_SERVICE_ACCOUNT value: eventing-broker-ingress - - name: BROKER_INGRESS_POLICY - value: allow_registered - name: BROKER_FILTER_IMAGE value: github.com/knative/eventing/cmd/broker/filter - name: BROKER_FILTER_SERVICE_ACCOUNT diff --git a/pkg/apis/eventing/v1alpha1/broker_types.go b/pkg/apis/eventing/v1alpha1/broker_types.go index 7e0c5a1c9be..cb119e1be3a 100644 --- a/pkg/apis/eventing/v1alpha1/broker_types.go +++ b/pkg/apis/eventing/v1alpha1/broker_types.go @@ -64,6 +64,10 @@ type BrokerSpec struct { // // +optional ChannelTemplate *ChannelSpec `json:"channelTemplate,omitempty"` + + // TODO probably make it an object. + // +optional + IngressPolicy string `json:"ingressPolicy,omitempty"` } var brokerCondSet = duckv1alpha1.NewLivingConditionSet(BrokerConditionIngress, BrokerConditionChannel, BrokerConditionFilter, BrokerConditionAddressable) diff --git a/pkg/reconciler/v1alpha1/broker/broker.go b/pkg/reconciler/v1alpha1/broker/broker.go index a2d0d835f69..3ad3854589b 100644 --- a/pkg/reconciler/v1alpha1/broker/broker.go +++ b/pkg/reconciler/v1alpha1/broker/broker.go @@ -74,7 +74,6 @@ type reconciler struct { ingressImage string ingressServiceAccountName string - ingressPolicy string filterImage string filterServiceAccountName string } @@ -85,7 +84,6 @@ var _ reconcile.Reconciler = &reconciler{} type ReconcilerArgs struct { IngressImage string IngressServiceAccountName string - IngressPolicy string FilterImage string FilterServiceAccountName string } @@ -101,7 +99,6 @@ func ProvideController(logger *zap.Logger, args ReconcilerArgs) func(manager.Man ingressImage: args.IngressImage, ingressServiceAccountName: args.IngressServiceAccountName, - ingressPolicy: args.IngressPolicy, filterImage: args.FilterImage, filterServiceAccountName: args.FilterServiceAccountName, }, @@ -433,7 +430,6 @@ func (r *reconciler) reconcileIngressDeployment(ctx context.Context, b *v1alpha1 Broker: b, Image: r.ingressImage, ServiceAccountName: r.ingressServiceAccountName, - Policy: r.ingressPolicy, ChannelAddress: c.Status.Address.Hostname, }) return r.reconcileDeployment(ctx, expected) diff --git a/pkg/reconciler/v1alpha1/broker/resources/ingress.go b/pkg/reconciler/v1alpha1/broker/resources/ingress.go index 2131f2d478b..aca1da121a5 100644 --- a/pkg/reconciler/v1alpha1/broker/resources/ingress.go +++ b/pkg/reconciler/v1alpha1/broker/resources/ingress.go @@ -31,7 +31,6 @@ import ( type IngressArgs struct { Broker *eventingv1alpha1.Broker Image string - Policy string ServiceAccountName string ChannelAddress string } @@ -82,7 +81,7 @@ func MakeIngress(args *IngressArgs) *appsv1.Deployment { }, { Name: "POLICY", - Value: args.Policy, + Value: args.Broker.Spec.IngressPolicy, }, }, }, From 02e6515f03d6f23e980f206d3c8968f16455631e Mon Sep 17 00:00:00 2001 From: nachocano Date: Thu, 28 Feb 2019 10:55:00 -0800 Subject: [PATCH 119/221] making header a constant. Should use the SDK instead. --- pkg/broker/ingress.go | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/pkg/broker/ingress.go b/pkg/broker/ingress.go index aac40d506e9..c3e6cc002fc 100644 --- a/pkg/broker/ingress.go +++ b/pkg/broker/ingress.go @@ -30,6 +30,11 @@ import ( const ( allowAny = "allow_any" allowRegisteredTypes = "allow_registered" + + // This header is for cloudevents spec 0.1. + // In the 0.2 version the HTTP header is called 'ce-type'. + // TODO use cloudevents sdk for doing encoding/decoding of events. + eventType = "Ce-Eventtype" ) type IngressPolicy interface { @@ -66,15 +71,15 @@ func (policy *AllowAnyPolicy) AllowMessage(namespace string, message *provisione } func (policy *AllowRegisteredPolicy) AllowMessage(namespace string, message *provisioners.Message) bool { - eventType := &eventingv1alpha1.EventType{} - name := message.Headers["Ce-Eventtype"] + et := &eventingv1alpha1.EventType{} + name := message.Headers[eventType] err := policy.client.Get(context.TODO(), types.NamespacedName{ Namespace: namespace, Name: name, }, - eventType) + et) if k8serrors.IsNotFound(err) { policy.logger.Warnf("EventType not found: %q", name) From a71b0de0782ea8e2625312f28ba1c80a8ef814bc Mon Sep 17 00:00:00 2001 From: nachocano Date: Thu, 28 Feb 2019 17:04:17 -0800 Subject: [PATCH 120/221] Adding dummy change to trigger event --- t.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t.yaml b/t.yaml index 0e2604dd595..6fdbe070d91 100644 --- a/t.yaml +++ b/t.yaml @@ -1,7 +1,7 @@ apiVersion: eventing.knative.dev/v1alpha1 kind: Trigger metadata: - name: t + name: trigger spec: subscriber: ref: From 383c411eceefae56ba2e3e4492e9a1f06b8f1c71 Mon Sep 17 00:00:00 2001 From: nachocano Date: Fri, 1 Mar 2019 12:02:29 -0800 Subject: [PATCH 121/221] Using cloudevents sdk but still needs to be updated. We should change our APIs to receive Events instead of Messages. --- Gopkg.lock | 14 +++ Gopkg.toml | 6 ++ cmd/broker/ingress/main.go | 35 ++++++- pkg/broker/ingress.go | 16 ++- third_party/VENDOR-LICENSE | 207 +++++++++++++++++++++++++++++++++++++ 5 files changed, 267 insertions(+), 11 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index e39d179ac4d..e9d0ecbaf9e 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -57,6 +57,19 @@ revision = "c618e605e15c0d7535f6c96ff8efbb0dba4fd66c" version = "v2.1.15" +[[projects]] + digest = "1:a12b641b81e00b8444bed01357098490ab769dbce31de3410b64c46a23a06287" + name = "github.com/cloudevents/sdk-go" + packages = [ + "pkg/cloudevents", + "pkg/cloudevents/datacodec", + "pkg/cloudevents/datacodec/json", + "pkg/cloudevents/datacodec/xml", + "pkg/cloudevents/types", + ] + pruneopts = "NUT" + revision = "d50361a5655081514f406b4e672d72e9886c17ad" + [[projects]] digest = "1:ffe9824d294da03b391f44e1ae8281281b4afc1bdaa9588c9097785e3af10cec" name = "github.com/davecgh/go-spew" @@ -1235,6 +1248,7 @@ "cloud.google.com/go/pubsub", "github.com/Shopify/sarama", "github.com/bsm/sarama-cluster", + "github.com/cloudevents/sdk-go/pkg/cloudevents", "github.com/fsnotify/fsnotify", "github.com/golang/glog", "github.com/google/go-cmp/cmp", diff --git a/Gopkg.toml b/Gopkg.toml index 5056356a75c..21f0b87e726 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -129,3 +129,9 @@ required = [ [[override]] name = "github.com/nats-io/nats-streaming-server" version = "0.11.0" + +# Use CloudEvents, master as of Feb 28, 2019 +# Will use releases as soon as they get releases going. +[[override]] + name = "github.com/cloudevents/sdk-go" + revision = "d50361a5655081514f406b4e672d72e9886c17ad" diff --git a/cmd/broker/ingress/main.go b/cmd/broker/ingress/main.go index 0c1ceafafeb..2a29d9a2499 100644 --- a/cmd/broker/ingress/main.go +++ b/cmd/broker/ingress/main.go @@ -35,12 +35,23 @@ import ( "go.uber.org/zap" "sigs.k8s.io/controller-runtime/pkg/client/config" "sigs.k8s.io/controller-runtime/pkg/manager" + + "github.com/cloudevents/sdk-go/pkg/cloudevents" + "github.com/cloudevents/sdk-go/pkg/cloudevents/types" ) const ( NAMESPACE = "NAMESPACE" CHANNEL = "CHANNEL" POLICY = "POLICY" + + // TODO should remove this constants once we start using cloudevents-sdk properly. + v1EventId = "Ce-Eventid" + v1EventType = "Ce-Eventtype" + v1EventSource = "Ce-Source" + v2EventId = "ce-id" + v2EventType = "ce-type" + v2EventSource = "ce-source" ) var ( @@ -140,9 +151,11 @@ func NewHandler(logger *zap.Logger, destination, policy string, client client.Cl return handler } +// TODO should receive a cloudevents.Event here instead of provisioners.Message func createReceiverFunction(f *Handler) func(provisioners.ChannelReference, *provisioners.Message) error { return func(c provisioners.ChannelReference, m *provisioners.Message) error { - if f.ingressPolicy.AllowMessage(c.Namespace, m) { + event := cloudEventFrom(m) + if f.ingressPolicy.AllowEvent(c.Namespace, &event) { return f.dispatch(m) } return nil @@ -175,3 +188,23 @@ func (r *runnableServer) Start(<-chan struct{}) error { r.logger.Info("Ingress Listening...", zap.String("Address", r.s.Addr)) return r.s.ListenAndServe() } + +// TODO this should be removed once we update the interfaces and start using cloudevents.Event instead of Message. +func cloudEventFrom(m *provisioners.Message) cloudevents.Event { + event := cloudevents.Event{} + if eventType, ok := m.Headers[v2EventType]; ok { + event.Context = cloudevents.EventContextV02{ + ID: m.Headers[v2EventId], + Type: eventType, + Source: *types.ParseURLRef(v2EventSource), + }.AsV02() + } else { + event.Context = cloudevents.EventContextV01{ + EventID: m.Headers[v1EventId], + EventType: m.Headers[v1EventType], + Source: *types.ParseURLRef(v1EventSource), + }.AsV01() + } + event.Data = m.Payload + return event +} diff --git a/pkg/broker/ingress.go b/pkg/broker/ingress.go index c3e6cc002fc..c423ec6ffa3 100644 --- a/pkg/broker/ingress.go +++ b/pkg/broker/ingress.go @@ -19,8 +19,9 @@ package broker import ( "context" + "github.com/cloudevents/sdk-go/pkg/cloudevents" + eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" - "github.com/knative/eventing/pkg/provisioners" "go.uber.org/zap" k8serrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/types" @@ -30,15 +31,10 @@ import ( const ( allowAny = "allow_any" allowRegisteredTypes = "allow_registered" - - // This header is for cloudevents spec 0.1. - // In the 0.2 version the HTTP header is called 'ce-type'. - // TODO use cloudevents sdk for doing encoding/decoding of events. - eventType = "Ce-Eventtype" ) type IngressPolicy interface { - AllowMessage(namespace string, message *provisioners.Message) bool + AllowEvent(namespace string, event *cloudevents.Event) bool } type AllowAnyPolicy struct{} @@ -66,13 +62,13 @@ func newIngressPolicy(logger *zap.SugaredLogger, client client.Client, policy st } } -func (policy *AllowAnyPolicy) AllowMessage(namespace string, message *provisioners.Message) bool { +func (policy *AllowAnyPolicy) AllowEvent(namespace string, event *cloudevents.Event) bool { return true } -func (policy *AllowRegisteredPolicy) AllowMessage(namespace string, message *provisioners.Message) bool { +func (policy *AllowRegisteredPolicy) AllowEvent(namespace string, event *cloudevents.Event) bool { et := &eventingv1alpha1.EventType{} - name := message.Headers[eventType] + name := event.Type() err := policy.client.Get(context.TODO(), types.NamespacedName{ diff --git a/third_party/VENDOR-LICENSE b/third_party/VENDOR-LICENSE index e7c5fe8e690..bdfec23c2a0 100644 --- a/third_party/VENDOR-LICENSE +++ b/third_party/VENDOR-LICENSE @@ -287,6 +287,213 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +=========================================================== +Import: github.com/knative/eventing/vendor/github.com/cloudevents/sdk-go + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + =========================================================== Import: github.com/knative/eventing/vendor/github.com/davecgh/go-spew From f6b218c8d0316f056b321ce3053819c7abddb3b2 Mon Sep 17 00:00:00 2001 From: nachocano Date: Fri, 1 Mar 2019 12:09:42 -0800 Subject: [PATCH 122/221] Adding cloudevents-sdk library --- vendor/github.com/cloudevents/sdk-go/LICENSE | 201 ++++++++++++++++ .../sdk-go/pkg/cloudevents/content_type.go | 34 +++ .../sdk-go/pkg/cloudevents/datacodec/codec.go | 48 ++++ .../pkg/cloudevents/datacodec/json/data.go | 66 ++++++ .../pkg/cloudevents/datacodec/xml/data.go | 59 +++++ .../cloudevents/sdk-go/pkg/cloudevents/doc.go | 86 +++++++ .../sdk-go/pkg/cloudevents/event.go | 73 ++++++ .../sdk-go/pkg/cloudevents/eventcontext.go | 34 +++ .../pkg/cloudevents/eventcontext_v01.go | 218 ++++++++++++++++++ .../pkg/cloudevents/eventcontext_v02.go | 203 ++++++++++++++++ .../pkg/cloudevents/eventcontext_v03.go | 181 +++++++++++++++ .../sdk-go/pkg/cloudevents/types/allocate.go | 36 +++ .../sdk-go/pkg/cloudevents/types/timestamp.go | 51 ++++ .../sdk-go/pkg/cloudevents/types/urlref.go | 44 ++++ 14 files changed, 1334 insertions(+) create mode 100644 vendor/github.com/cloudevents/sdk-go/LICENSE create mode 100644 vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/content_type.go create mode 100644 vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/datacodec/codec.go create mode 100644 vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/datacodec/json/data.go create mode 100644 vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/datacodec/xml/data.go create mode 100644 vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/doc.go create mode 100644 vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/event.go create mode 100644 vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/eventcontext.go create mode 100644 vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/eventcontext_v01.go create mode 100644 vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/eventcontext_v02.go create mode 100644 vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/eventcontext_v03.go create mode 100644 vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/types/allocate.go create mode 100644 vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/types/timestamp.go create mode 100644 vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/types/urlref.go diff --git a/vendor/github.com/cloudevents/sdk-go/LICENSE b/vendor/github.com/cloudevents/sdk-go/LICENSE new file mode 100644 index 00000000000..261eeb9e9f8 --- /dev/null +++ b/vendor/github.com/cloudevents/sdk-go/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/content_type.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/content_type.go new file mode 100644 index 00000000000..077ff2bd970 --- /dev/null +++ b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/content_type.go @@ -0,0 +1,34 @@ +package cloudevents + +const ( + ApplicationJSON = "application/json" + ApplicationXML = "application/xml" + ApplicationCloudEventsJSON = "application/cloudevents+json" + ApplicationCloudEventsBatchJSON = "application/cloudevents-batch+json" +) + +// StringOfApplicationJSON returns a string pointer to "application/json" +func StringOfApplicationJSON() *string { + a := ApplicationJSON + return &a +} + +// StringOfApplicationXML returns a string pointer to "application/xml" +func StringOfApplicationXML() *string { + a := ApplicationXML + return &a +} + +// StringOfApplicationCloudEventsJSON returns a string pointer to +// "application/cloudevents+json" +func StringOfApplicationCloudEventsJSON() *string { + a := ApplicationCloudEventsJSON + return &a +} + +// StringOfApplicationCloudEventsBatchJSON returns a string pointer to +// "application/cloudevents-batch+json" +func StringOfApplicationCloudEventsBatchJSON() *string { + a := ApplicationCloudEventsBatchJSON + return &a +} diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/datacodec/codec.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/datacodec/codec.go new file mode 100644 index 00000000000..1f6ce63d365 --- /dev/null +++ b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/datacodec/codec.go @@ -0,0 +1,48 @@ +package datacodec + +import ( + "fmt" + "github.com/cloudevents/sdk-go/pkg/cloudevents/datacodec/json" + "github.com/cloudevents/sdk-go/pkg/cloudevents/datacodec/xml" +) + +type Decoder func(in, out interface{}) error +type Encoder func(in interface{}) ([]byte, error) + +var decoder map[string]Decoder +var encoder map[string]Encoder + +func init() { + decoder = make(map[string]Decoder, 10) + encoder = make(map[string]Encoder, 10) + + AddDecoder("", json.Decode) + AddDecoder("application/json", json.Decode) + AddDecoder("application/xml", xml.Decode) + + AddEncoder("", json.Encode) + AddEncoder("application/json", json.Encode) + AddEncoder("application/xml", xml.Encode) +} + +func AddDecoder(contentType string, fn Decoder) { + decoder[contentType] = fn +} + +func AddEncoder(contentType string, fn Encoder) { + encoder[contentType] = fn +} + +func Decode(contentType string, in, out interface{}) error { + if fn, ok := decoder[contentType]; ok { + return fn(in, out) + } + return fmt.Errorf("[decode] unsupported content type: %q", contentType) +} + +func Encode(contentType string, in interface{}) ([]byte, error) { + if fn, ok := encoder[contentType]; ok { + return fn(in) + } + return nil, fmt.Errorf("[encode] unsupported content type: %q", contentType) +} diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/datacodec/json/data.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/datacodec/json/data.go new file mode 100644 index 00000000000..38d75566713 --- /dev/null +++ b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/datacodec/json/data.go @@ -0,0 +1,66 @@ +package json + +import ( + "encoding/json" + "fmt" + "reflect" + "strconv" +) + +func Decode(in, out interface{}) error { + if in == nil { + return nil + } + if out == nil { + return fmt.Errorf("out is nil") + } + + b, ok := in.([]byte) // TODO: I think there is fancy marshaling happening here. Fix with reflection? + if !ok { + var err error + b, err = json.Marshal(in) + if err != nil { + return fmt.Errorf("[json] failed to marshal in: %s", err.Error()) + } + } + + // TODO: the spec says json could be just data... At the moment we expect wrapped. + if len(b) > 1 && (b[0] == byte('"') || (b[0] == byte('\\') && b[1] == byte('"'))) { + s, err := strconv.Unquote(string(b)) + if err != nil { + return fmt.Errorf("[json] failed to unquote in: %s", err.Error()) + } + if len(s) > 0 && (s[0] == '{' || s[0] == '[') { + // looks like json, use it + b = []byte(s) + } + } + + if err := json.Unmarshal(b, out); err != nil { + return fmt.Errorf("[json] found bytes \"%s\", but failed to unmarshal: %s", string(b), err.Error()) + } + return nil +} + +func Encode(in interface{}) ([]byte, error) { + if in == nil { + return nil, nil + } + + it := reflect.TypeOf(in) + switch it.Kind() { + case reflect.Slice: + if it.Elem().Kind() == reflect.Uint8 { + + if b, ok := in.([]byte); ok && len(b) > 0 { + // check to see if it is a pre-encoded byte string. + if b[0] == byte('"') || b[0] == byte('{') || b[0] == byte('[') { + return b, nil + } + } + + } + } + + return json.Marshal(in) +} diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/datacodec/xml/data.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/datacodec/xml/data.go new file mode 100644 index 00000000000..fb36f2eb285 --- /dev/null +++ b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/datacodec/xml/data.go @@ -0,0 +1,59 @@ +package xml + +import ( + "encoding/base64" + "encoding/xml" + "fmt" + "strconv" +) + +func Decode(in, out interface{}) error { + if in == nil { + return nil + } + + b, ok := in.([]byte) + if !ok { + var err error + b, err = xml.Marshal(in) + if err != nil { + return fmt.Errorf("[xml] failed to marshal in: %s", err.Error()) + } + } + + // If the message is encoded as a base64 block as a string, we need to + // decode that first before trying to unmarshal the bytes + if len(b) > 1 && (b[0] == byte('"') || (b[0] == byte('\\') && b[1] == byte('"'))) { + s, err := strconv.Unquote(string(b)) + if err != nil { + return err + } + if len(s) > 0 && s[0] == '<' { + // looks like xml, use it + b = []byte(s) + } else if len(s) > 0 { + // looks like base64, decode + bs, err := base64.StdEncoding.DecodeString(s) + if err != nil { + return err + } + b = bs + } + } + + if err := xml.Unmarshal(b, out); err != nil { + return fmt.Errorf("[xml] found bytes, but failed to unmarshal: %s %s", err.Error(), string(b)) + } + return nil +} + +func Encode(in interface{}) ([]byte, error) { + if b, ok := in.([]byte); ok { + // check to see if it is a pre-encoded byte string. + if len(b) > 0 && b[0] == byte('"') { + return b, nil + } + } + + return xml.Marshal(in) +} diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/doc.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/doc.go new file mode 100644 index 00000000000..cfb6eac590c --- /dev/null +++ b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/doc.go @@ -0,0 +1,86 @@ +/* +Package cloudevents provides primitives to work with CloudEvents specification: https://github.com/cloudevents/spec. + + +Parsing Event from HTTP Request: + // req is *http.Request + event, err := cloudEvents.FromHTTPRequest(req) + if err != nil { + panic("Unable to parse event from http Request: " + err.String()) + } + + +Creating a minimal CloudEvent in version 0.1: + import "github.com/cloudevents/sdk-go/pkg/cloudevents/v01" + event := v01.Event{ + EventType: "com.example.file.created", + Source: "/providers/Example.COM/storage/account#fileServices/default/{new-file}", + EventID: "ea35b24ede421", + } + + +The goal of this package is to provide support for all released versions of CloudEvents, ideally while maintaining +the same API. It will use semantic versioning with following rules: +* MAJOR version increments when backwards incompatible changes is introduced. +* MINOR version increments when backwards compatible feature is introduced INCLUDING support for new CloudEvents version. +* PATCH version increments when a backwards compatible bug fix is introduced. +*/ +package cloudevents + +/* + +New plan. + +Everything gets converted into the Canonical form of the event, this +then can select a transport, the transport provides encodings. + +At the moment we have cloudevents.[v01, v02] + +Canonical form holds an encoded data packet that takes in a provided Codec + +Canonical form has two members: Context, and Data + + +Sending: +cloudevents.[v01, v02] -> { Codec.Encode -> HttpMessage -> Transport[Http] } + +Receiving: +{ Transport[Http] -> HttpMessage -> Codec.Decode } -> cloudevents.[v01, v02] + +Note: Transport and Codec are grouped. + +Transport Codecs supported: +[Binary, Structured, StructuredMirrorHeaders] + + +## Working with inner data: +cloudevents.[v01, v02].Decode(DataCodec) -> custom data + +Working with inner data, + +Sending: +cloudevents.[v01, v02].data -> DataCodec.Decode -> custom data + +Receiving: +custom data -> DataCodec.Encode -> cloudevents.[v01, v02].data,contentType + +Data Codecs supported: +[json, xml, base64, text] + + +This imples that there is only one canonical form and it evolves and is marked +deprecated as the model evolves. + +Spec says: + +Event[Context, Data] -> Message + +Http Message should have: + +Headers +Body +ContentType +ContentLength + + +*/ diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/event.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/event.go new file mode 100644 index 00000000000..5964d612484 --- /dev/null +++ b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/event.go @@ -0,0 +1,73 @@ +package cloudevents + +import ( + "fmt" + "github.com/cloudevents/sdk-go/pkg/cloudevents/datacodec" + "strings" +) + +// Event represents the canonical representation of a CloudEvent. +type Event struct { + Context EventContext + Data interface{} +} + +func (e Event) DataAs(data interface{}) error { + return datacodec.Decode(e.Context.GetDataMediaType(), e.Data, data) +} + +func (e Event) SpecVersion() string { + return e.Context.GetSpecVersion() +} + +func (e Event) Type() string { + return e.Context.GetType() +} + +func (e Event) DataContentType() string { + return e.Context.GetDataContentType() +} + +func (e Event) Validate() error { + if e.Context == nil { + return fmt.Errorf("every event conforming to the CloudEvents specification MUST include a context") + } + + if err := e.Context.Validate(); err != nil { + return err + } + + // TODO: validate data. + + return nil +} + +func (e Event) String() string { + sb := strings.Builder{} + + if s := e.SpecVersion(); s != "" { + if sb.Len() > 0 { + sb.WriteString("\n") + } + sb.WriteString("SpecVersion: ") + sb.WriteString(s) + } + + if s := e.Type(); s != "" { + if sb.Len() > 0 { + sb.WriteString("\n") + } + sb.WriteString("Type: ") + sb.WriteString(s) + } + + if s := e.DataContentType(); s != "" { + if sb.Len() > 0 { + sb.WriteString("\n") + } + sb.WriteString("DataContentType: ") + sb.WriteString(s) + } + + return sb.String() +} diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/eventcontext.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/eventcontext.go new file mode 100644 index 00000000000..1f5b4d943c8 --- /dev/null +++ b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/eventcontext.go @@ -0,0 +1,34 @@ +package cloudevents + +type EventContext interface { + // AsV01 provides a translation from whatever the "native" encoding of the + // CloudEvent was to the equivalent in v0.1 field names, moving fields to or + // from extensions as necessary. + AsV01() EventContextV01 + + // AsV02 provides a translation from whatever the "native" encoding of the + // CloudEvent was to the equivalent in v0.2 field names, moving fields to or + // from extensions as necessary. + AsV02() EventContextV02 + + // AsV03 provides a translation from whatever the "native" encoding of the + // CloudEvent was to the equivalent in v0.3 field names, moving fields to or + // from extensions as necessary. + AsV03() EventContextV03 + + // GetDataContentType returns content type on the context. + GetDataContentType() string + + // GetDataMediaType returns the MIME media type for encoded data, which is + // needed by both encoding and decoding. + GetDataMediaType() string + + // GetSpecVersion returns the native CloudEvents Spec version of the event + // context. + GetSpecVersion() string + + // GetType returns the CloudEvents type from the context. + GetType() string + + Validate() error +} diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/eventcontext_v01.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/eventcontext_v01.go new file mode 100644 index 00000000000..318df337ac2 --- /dev/null +++ b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/eventcontext_v01.go @@ -0,0 +1,218 @@ +package cloudevents + +import ( + "fmt" + "github.com/cloudevents/sdk-go/pkg/cloudevents/types" + "log" + "mime" + "strings" +) + +const ( + // CloudEventsVersionV01 represents the version 0.1 of the CloudEvents spec. + CloudEventsVersionV01 = "0.1" +) + +// EventContextV01 holds standard metadata about an event. See +// https://github.com/cloudevents/spec/blob/v0.1/spec.md#context-attributes for +// details on these fields. +type EventContextV01 struct { + // The version of the CloudEvents specification used by the event. + CloudEventsVersion string `json:"cloudEventsVersion,omitempty"` + // ID of the event; must be non-empty and unique within the scope of the producer. + EventID string `json:"eventID"` + // Timestamp when the event happened. + EventTime *types.Timestamp `json:"eventTime,omitempty"` + // Type of occurrence which has happened. + EventType string `json:"eventType"` + // The version of the `eventType`; this is producer-specific. + EventTypeVersion *string `json:"eventTypeVersion,omitempty"` + // A link to the schema that the `data` attribute adheres to. + SchemaURL *types.URLRef `json:"schemaURL,omitempty"` + // A MIME (RFC 2046) string describing the media type of `data`. + // TODO: Should an empty string assume `application/json`, or auto-detect the content? + ContentType *string `json:"contentType,omitempty"` + // A URI describing the event producer. + Source types.URLRef `json:"source"` + // Additional metadata without a well-defined structure. + Extensions map[string]interface{} `json:"extensions,omitempty"` +} + +var _ EventContext = (*EventContextV01)(nil) + +func (ec EventContextV01) GetSpecVersion() string { + if ec.CloudEventsVersion != "" { + return ec.CloudEventsVersion + } + return CloudEventsVersionV01 +} + +func (ec EventContextV01) GetDataContentType() string { + if ec.ContentType != nil { + return *ec.ContentType + } + return "" +} + +func (ec EventContextV01) GetDataMediaType() string { + if ec.ContentType != nil { + mediaType, _, err := mime.ParseMediaType(*ec.ContentType) + if err != nil { + log.Printf("failed to parse media type from ContentType: %s", err) + return "" + } + return mediaType + } + return "" +} + +func (ec EventContextV01) GetType() string { + return ec.EventType +} + +func (ec EventContextV01) AsV01() EventContextV01 { + ec.CloudEventsVersion = CloudEventsVersionV01 + return ec +} + +func (ec EventContextV01) AsV02() EventContextV02 { + ret := EventContextV02{ + SpecVersion: CloudEventsVersionV02, + Type: ec.EventType, + Source: ec.Source, + ID: ec.EventID, + Time: ec.EventTime, + SchemaURL: ec.SchemaURL, + ContentType: ec.ContentType, + Extensions: make(map[string]interface{}), + } + + // eventTypeVersion was retired in v0.2, so put it in an extension. + if ec.EventTypeVersion != nil { + ret.Extensions["eventTypeVersion"] = *ec.EventTypeVersion + } + if ec.Extensions != nil { + for k, v := range ec.Extensions { + ret.Extensions[k] = v + } + } + if len(ret.Extensions) == 0 { + ret.Extensions = nil + } + return ret +} + +func (ec EventContextV01) AsV03() EventContextV03 { + ecv2 := ec.AsV02() + return ecv2.AsV03() +} + +// Validate returns errors based on requirements from the CloudEvents spec. +// For more details, see https://github.com/cloudevents/spec/blob/v0.1/spec.md +func (ec EventContextV01) Validate() error { + errors := []string(nil) + + // eventType + // Type: String + // Constraints: + // REQUIRED + // MUST be a non-empty string + // SHOULD be prefixed with a reverse-DNS name. The prefixed domain dictates the organization which defines the semantics of this event type. + eventType := strings.TrimSpace(ec.EventType) + if eventType == "" { + errors = append(errors, "eventType: MUST be a non-empty string") + } + + // eventTypeVersion + // Type: String + // Constraints: + // OPTIONAL + // If present, MUST be a non-empty string + if ec.EventTypeVersion != nil { + eventTypeVersion := strings.TrimSpace(*ec.EventTypeVersion) + if eventTypeVersion == "" { + errors = append(errors, "eventTypeVersion: if present, MUST be a non-empty string") + } + } + + // cloudEventsVersion + // Type: String + // Constraints: + // REQUIRED + // MUST be a non-empty string + cloudEventsVersion := strings.TrimSpace(ec.CloudEventsVersion) + if cloudEventsVersion == "" { + errors = append(errors, "cloudEventsVersion: MUST be a non-empty string") + } + + // source + // Type: URI + // Constraints: + // REQUIRED + source := strings.TrimSpace(ec.Source.String()) + if source == "" { + errors = append(errors, "source: REQUIRED") + } + + // eventID + // Type: String + // Constraints: + // REQUIRED + // MUST be a non-empty string + // MUST be unique within the scope of the producer + eventID := strings.TrimSpace(ec.EventID) + if eventID == "" { + errors = append(errors, "eventID: MUST be a non-empty string") + + // no way to test "MUST be unique within the scope of the producer" + } + + // eventTime + // Type: Timestamp + // Constraints: + // OPTIONAL + // If present, MUST adhere to the format specified in RFC 3339 + // --> no need to test this, no way to set the eventTime without it being valid. + + // schemaURL + // Type: URI + // Constraints: + // OPTIONAL + // If present, MUST adhere to the format specified in RFC 3986 + if ec.SchemaURL != nil { + schemaURL := strings.TrimSpace(ec.SchemaURL.String()) + // empty string is not RFC 3986 compatible. + if schemaURL == "" { + errors = append(errors, "schemaURL: if present, MUST adhere to the format specified in RFC 3986") + } + } + + // contentType + // Type: String per RFC 2046 + // Constraints: + // OPTIONAL + // If present, MUST adhere to the format specified in RFC 2046 + if ec.ContentType != nil { + contentType := strings.TrimSpace(*ec.ContentType) + if contentType == "" { + // TODO: need to test for RFC 2046 + errors = append(errors, "contentType: if present, MUST adhere to the format specified in RFC 2046") + } + } + + // extensions + // Type: Map + // Constraints: + // OPTIONAL + // If present, MUST contain at least one entry + if ec.Extensions != nil { + if len(ec.Extensions) == 0 { + errors = append(errors, "extensions: if present, MUST contain at least one entry") + } + } + + if len(errors) > 0 { + return fmt.Errorf(strings.Join(errors, "\n")) + } + return nil +} diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/eventcontext_v02.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/eventcontext_v02.go new file mode 100644 index 00000000000..c2bdba2d246 --- /dev/null +++ b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/eventcontext_v02.go @@ -0,0 +1,203 @@ +package cloudevents + +import ( + "fmt" + "github.com/cloudevents/sdk-go/pkg/cloudevents/types" + "log" + "mime" + "strings" +) + +const ( + // CloudEventsVersionV02 represents the version 0.2 of the CloudEvents spec. + CloudEventsVersionV02 = "0.2" +) + +// EventContextV02 represents the non-data attributes of a CloudEvents v0.2 +// event. +type EventContextV02 struct { + // The version of the CloudEvents specification used by the event. + SpecVersion string `json:"specversion"` + // The type of the occurrence which has happened. + Type string `json:"type"` + // A URI describing the event producer. + Source types.URLRef `json:"source"` + // ID of the event; must be non-empty and unique within the scope of the producer. + ID string `json:"id"` + // Timestamp when the event happened. + Time *types.Timestamp `json:"time,omitempty"` + // A link to the schema that the `data` attribute adheres to. + SchemaURL *types.URLRef `json:"schemaurl,omitempty"` + // A MIME (RFC2046) string describing the media type of `data`. + // TODO: Should an empty string assume `application/json`, `application/octet-stream`, or auto-detect the content? + ContentType *string `json:"contenttype,omitempty"` + // Additional extension metadata beyond the base spec. + Extensions map[string]interface{} `json:"-,omitempty"` // TODO: decide how we want extensions to be inserted +} + +var _ EventContext = (*EventContextV02)(nil) + +func (ec EventContextV02) GetSpecVersion() string { + if ec.SpecVersion != "" { + return ec.SpecVersion + } + return CloudEventsVersionV02 +} + +func (ec EventContextV02) GetDataContentType() string { + if ec.ContentType != nil { + return *ec.ContentType + } + return "" +} + +func (ec EventContextV02) GetDataMediaType() string { + if ec.ContentType != nil { + mediaType, _, err := mime.ParseMediaType(*ec.ContentType) + if err != nil { + log.Printf("failed to parse media type from ContentType: %s", err) + return "" + } + return mediaType + } + return "" +} + +func (ec EventContextV02) GetType() string { + return ec.Type +} + +func (ec EventContextV02) AsV01() EventContextV01 { + ret := EventContextV01{ + CloudEventsVersion: CloudEventsVersionV01, + EventID: ec.ID, + EventTime: ec.Time, + EventType: ec.Type, + SchemaURL: ec.SchemaURL, + Source: ec.Source, + ContentType: ec.ContentType, + Extensions: make(map[string]interface{}), + } + + for k, v := range ec.Extensions { + // eventTypeVersion was retired in v0.2 + if strings.EqualFold(k, "eventTypeVersion") { + etv, ok := v.(string) + if ok && etv != "" { + ret.EventTypeVersion = &etv + } + continue + } + ret.Extensions[k] = v + } + if len(ret.Extensions) == 0 { + ret.Extensions = nil + } + return ret +} + +func (ec EventContextV02) AsV02() EventContextV02 { + ec.SpecVersion = CloudEventsVersionV02 + return ec +} + +func (ec EventContextV02) AsV03() EventContextV03 { + ret := EventContextV03{ + SpecVersion: CloudEventsVersionV03, + ID: ec.ID, + Time: ec.Time, + Type: ec.Type, + SchemaURL: ec.SchemaURL, + DataContentType: ec.ContentType, + Source: ec.Source, + Extensions: ec.Extensions, + } + return ret +} + +// Validate returns errors based on requirements from the CloudEvents spec. +// For more details, see https://github.com/cloudevents/spec/blob/v0.2/spec.md +func (ec EventContextV02) Validate() error { + errors := []string(nil) + + // type + // Type: String + // Constraints: + // REQUIRED + // MUST be a non-empty string + // SHOULD be prefixed with a reverse-DNS name. The prefixed domain dictates the organization which defines the semantics of this event type. + eventType := strings.TrimSpace(ec.Type) + if eventType == "" { + errors = append(errors, "type: MUST be a non-empty string") + } + + // specversion + // Type: String + // Constraints: + // REQUIRED + // MUST be a non-empty string + specVersion := strings.TrimSpace(ec.SpecVersion) + if specVersion == "" { + errors = append(errors, "specversion: MUST be a non-empty string") + } + + // source + // Type: URI-reference + // Constraints: + // REQUIRED + source := strings.TrimSpace(ec.Source.String()) + if source == "" { + errors = append(errors, "source: REQUIRED") + } + + // id + // Type: String + // Constraints: + // REQUIRED + // MUST be a non-empty string + // MUST be unique within the scope of the producer + id := strings.TrimSpace(ec.ID) + if id == "" { + errors = append(errors, "id: MUST be a non-empty string") + + // no way to test "MUST be unique within the scope of the producer" + } + + // time + // Type: Timestamp + // Constraints: + // OPTIONAL + // If present, MUST adhere to the format specified in RFC 3339 + // --> no need to test this, no way to set the time without it being valid. + + // schemaurl + // Type: URI + // Constraints: + // OPTIONAL + // If present, MUST adhere to the format specified in RFC 3986 + if ec.SchemaURL != nil { + schemaURL := strings.TrimSpace(ec.SchemaURL.String()) + // empty string is not RFC 3986 compatible. + if schemaURL == "" { + errors = append(errors, "schemaurl: if present, MUST adhere to the format specified in RFC 3986") + } + } + + // contenttype + // Type: String per RFC 2046 + // Constraints: + // OPTIONAL + // If present, MUST adhere to the format specified in RFC 2046 + if ec.ContentType != nil { + contentType := strings.TrimSpace(*ec.ContentType) + if contentType == "" { + // TODO: need to test for RFC 2046 + errors = append(errors, "contenttype: if present, MUST adhere to the format specified in RFC 2046") + } + } + + if len(errors) > 0 { + return fmt.Errorf(strings.Join(errors, "\n")) + } + return nil +} diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/eventcontext_v03.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/eventcontext_v03.go new file mode 100644 index 00000000000..465a815d1c9 --- /dev/null +++ b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/eventcontext_v03.go @@ -0,0 +1,181 @@ +package cloudevents + +import ( + "fmt" + "github.com/cloudevents/sdk-go/pkg/cloudevents/types" + "log" + "mime" + "strings" +) + +// WIP: AS OF FEB 19, 2019 + +const ( + // CloudEventsVersionV03 represents the version 0.3 of the CloudEvents spec. + CloudEventsVersionV03 = "0.3" +) + +// EventContextV03 represents the non-data attributes of a CloudEvents v0.3 +// event. +type EventContextV03 struct { + // SpecVersion - The version of the CloudEvents specification used by the event. + SpecVersion string `json:"specversion"` + // Type - The type of the occurrence which has happened. + Type string `json:"type"` + // Source - A URI describing the event producer. + Source types.URLRef `json:"source"` + // ID of the event; must be non-empty and unique within the scope of the producer. + ID string `json:"id"` + // Time - A Timestamp when the event happened. + Time *types.Timestamp `json:"time,omitempty"` + // SchemaURL - A link to the schema that the `data` attribute adheres to. + SchemaURL *types.URLRef `json:"schemaurl,omitempty"` + // GetDataMediaType - A MIME (RFC2046) string describing the media type of `data`. + // TODO: Should an empty string assume `application/json`, `application/octet-stream`, or auto-detect the content? + DataContentType *string `json:"datacontenttype,omitempty"` + // Extensions - Additional extension metadata beyond the base spec. + Extensions map[string]interface{} `json:"-,omitempty"` // TODO: decide how we want extensions to be inserted +} + +var _ EventContext = (*EventContextV03)(nil) + +func (ec EventContextV03) GetSpecVersion() string { + if ec.SpecVersion != "" { + return ec.SpecVersion + } + return CloudEventsVersionV03 +} + +func (ec EventContextV03) GetDataContentType() string { + if ec.DataContentType != nil { + return *ec.DataContentType + } + return "" +} + +func (ec EventContextV03) GetDataMediaType() string { + if ec.DataContentType != nil { + mediaType, _, err := mime.ParseMediaType(*ec.DataContentType) + if err != nil { + log.Printf("failed to parse media type from DataContentType: %s", err) + return "" + } + return mediaType + } + return "" +} +func (ec EventContextV03) GetType() string { + return ec.Type +} + +func (ec EventContextV03) AsV01() EventContextV01 { + ecv2 := ec.AsV02() + return ecv2.AsV01() +} + +func (ec EventContextV03) AsV02() EventContextV02 { + ret := EventContextV02{ + SpecVersion: CloudEventsVersionV02, + ID: ec.ID, + Time: ec.Time, + Type: ec.Type, + SchemaURL: ec.SchemaURL, + ContentType: ec.DataContentType, + Source: ec.Source, + Extensions: ec.Extensions, + } + return ret +} + +func (ec EventContextV03) AsV03() EventContextV03 { + ec.SpecVersion = CloudEventsVersionV03 + return ec +} + +// Validate returns errors based on requirements from the CloudEvents spec. +// For more details, see https://github.com/cloudevents/spec/blob/master/spec.md +// As of Feb 26, 2019, commit 17c32ea26baf7714ad027d9917d03d2fff79fc7e +func (ec EventContextV03) Validate() error { + errors := []string(nil) + + // type + // Type: String + // Constraints: + // REQUIRED + // MUST be a non-empty string + // SHOULD be prefixed with a reverse-DNS name. The prefixed domain dictates the organization which defines the semantics of this event type. + eventType := strings.TrimSpace(ec.Type) + if eventType == "" { + errors = append(errors, "type: MUST be a non-empty string") + } + + // specversion + // Type: String + // Constraints: + // REQUIRED + // MUST be a non-empty string + specVersion := strings.TrimSpace(ec.SpecVersion) + if specVersion == "" { + errors = append(errors, "specversion: MUST be a non-empty string") + } + + // source + // Type: URI-reference + // Constraints: + // REQUIRED + source := strings.TrimSpace(ec.Source.String()) + if source == "" { + errors = append(errors, "source: REQUIRED") + } + + // id + // Type: String + // Constraints: + // REQUIRED + // MUST be a non-empty string + // MUST be unique within the scope of the producer + id := strings.TrimSpace(ec.ID) + if id == "" { + errors = append(errors, "id: MUST be a non-empty string") + + // no way to test "MUST be unique within the scope of the producer" + } + + // time + // Type: Timestamp + // Constraints: + // OPTIONAL + // If present, MUST adhere to the format specified in RFC 3339 + // --> no need to test this, no way to set the time without it being valid. + + // schemaurl + // Type: URI + // Constraints: + // OPTIONAL + // If present, MUST adhere to the format specified in RFC 3986 + if ec.SchemaURL != nil { + schemaURL := strings.TrimSpace(ec.SchemaURL.String()) + // empty string is not RFC 3986 compatible. + if schemaURL == "" { + errors = append(errors, "schemaurl: if present, MUST adhere to the format specified in RFC 3986") + } + } + + // datacontenttype + // Type: String per RFC 2046 + // Constraints: + // OPTIONAL + // If present, MUST adhere to the format specified in RFC 2046 + if ec.DataContentType != nil { + dataContentType := strings.TrimSpace(*ec.DataContentType) + if dataContentType == "" { + // TODO: need to test for RFC 2046 + errors = append(errors, "datacontenttype: if present, MUST adhere to the format specified in RFC 2046") + } + } + + if len(errors) > 0 { + return fmt.Errorf(strings.Join(errors, "\n")) + } + return nil +} diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/types/allocate.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/types/allocate.go new file mode 100644 index 00000000000..00a4870f900 --- /dev/null +++ b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/types/allocate.go @@ -0,0 +1,36 @@ +package types + +import "reflect" + +// Allocates allocates a new instance of type t and returns: +// asPtr is of type t if t is a pointer type and of type &t otherwise +// asValue is a Value of type t pointing to the same data as asPtr +func Allocate(obj interface{}) (asPtr interface{}, asValue reflect.Value) { + if obj == nil { + return nil, reflect.Value{} + } + + switch t := reflect.TypeOf(obj); t.Kind() { + case reflect.Ptr: + reflectPtr := reflect.New(t.Elem()) + asPtr = reflectPtr.Interface() + asValue = reflectPtr + case reflect.Map: + reflectPtr := reflect.MakeMap(t) + asPtr = reflectPtr.Interface() + asValue = reflectPtr + case reflect.String: + reflectPtr := reflect.New(t) + asPtr = "" + asValue = reflectPtr.Elem() + case reflect.Slice: + reflectPtr := reflect.MakeSlice(t, 0, 0) + asPtr = reflectPtr.Interface() + asValue = reflectPtr + default: + reflectPtr := reflect.New(t) + asPtr = reflectPtr.Interface() + asValue = reflectPtr.Elem() + } + return +} diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/types/timestamp.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/types/timestamp.go new file mode 100644 index 00000000000..b535e5dad6d --- /dev/null +++ b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/types/timestamp.go @@ -0,0 +1,51 @@ +package types + +import ( + "encoding/json" + "fmt" + "time" +) + +type Timestamp struct { + time.Time +} + +func ParseTimestamp(t string) *Timestamp { + if t == "" { + return nil + } + timestamp, err := time.Parse(time.RFC3339Nano, t) + if err != nil { + return nil + } + return &Timestamp{Time: timestamp} +} + +// This allows json marshaling to always be in RFC3339Nano format. +func (t *Timestamp) MarshalJSON() ([]byte, error) { + if t == nil || t.IsZero() { + return []byte(`""`), nil + } + rfc3339 := fmt.Sprintf("%q", t.Format(time.RFC3339Nano)) + return []byte(rfc3339), nil +} + +func (t *Timestamp) UnmarshalJSON(b []byte) error { + var timestamp string + if err := json.Unmarshal(b, ×tamp); err != nil { + return err + } + pt := ParseTimestamp(timestamp) + if pt != nil { + *t = *pt + } + return nil +} + +func (t *Timestamp) String() string { + if t == nil { + return time.Time{}.Format(time.RFC3339Nano) + } + + return t.Format(time.RFC3339Nano) +} diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/types/urlref.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/types/urlref.go new file mode 100644 index 00000000000..0898e4ece8e --- /dev/null +++ b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/types/urlref.go @@ -0,0 +1,44 @@ +package types + +import ( + "encoding/json" + "fmt" + "net/url" +) + +type URLRef struct { + url.URL +} + +func ParseURLRef(u string) *URLRef { + if u == "" { + return nil + } + pu, err := url.Parse(u) + if err != nil { + return nil + } + return &URLRef{URL: *pu} +} + +// This allows json marshaling to always be in RFC3339Nano format. +func (u URLRef) MarshalJSON() ([]byte, error) { + b := fmt.Sprintf("%q", u.String()) + return []byte(b), nil +} + +func (u *URLRef) UnmarshalJSON(b []byte) error { + var ref string + if err := json.Unmarshal(b, &ref); err != nil { + return err + } + *u = *ParseURLRef(ref) + return nil +} + +func (u *URLRef) String() string { + if u == nil { + return "" + } + return u.URL.String() +} From f28f41aaa08dfe1b1a8a2510404aaddf79675ca8 Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Sun, 3 Mar 2019 20:00:42 -0800 Subject: [PATCH 123/221] Invalid eventtype --- e1.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 e1.yaml diff --git a/e1.yaml b/e1.yaml new file mode 100644 index 00000000000..65e25cffa27 --- /dev/null +++ b/e1.yaml @@ -0,0 +1,8 @@ +apiVersion: eventing.knative.dev/v1alpha1 +kind: EventType +metadata: + name: dev.knative.source.bitbucket.pullrequest:created +spec: + source: https://api.bitbucket.org/api/2.0/pullrequests/pullrequest_id + schema: http://foo2.example/schema + From edcab3e8419e898a6b05c26fa9c8ad984d5ab4ea Mon Sep 17 00:00:00 2001 From: Adam Harwayne Date: Wed, 6 Mar 2019 15:12:39 -0800 Subject: [PATCH 124/221] Initial docs for the Broker. --- docs/broker/README.md | 138 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 docs/broker/README.md diff --git a/docs/broker/README.md b/docs/broker/README.md new file mode 100644 index 00000000000..5f5e2e35b41 --- /dev/null +++ b/docs/broker/README.md @@ -0,0 +1,138 @@ +## Broker and Trigger CRDs + +The Broker and Trigger CRDs, both in `eventing.knative.dev/v1alpha1`, are +interdependent. + +#### Broker + +Broker represents an 'event mesh'. Events are sent to the Broker's ingress and +are then sent to any subscribers that are interested in that event. Once inside +a Broker, all metadata other than the CloudEvent is stripped away (e.g. unless +set as a CloudEvent attribute, there is no concept of how this event entered the +Broker). + +Example: + +```yaml +apiVersion: eventing.knative.dev/v1alpha1 +kind: Broker +metadata: + name: default +spec: + channelTemplate: + provisioner: + apiVersion: eventing.knative.dev/v1alpha1 + kind: ClusterChannelProvisioner + name: gcp-pubsub +``` + +#### Trigger + +Trigger represents a desire to subscribe to events from a specific Broker. Basic +filtering on the types of events is provided. + +Example: + +```yaml +apiVersion: eventing.knative.dev/v1alpha1 +kind: Trigger +metadata: + name: my-service-trigger +spec: + filter: + sourceAndType: + type: dev.knative.foo.bar + subscriber: + ref: + apiVersion: serving.knative.dev/v1alpha1 + kind: Service + name: my-service +``` + +## Usage + +The easiest way to get started, is to annotate your namespace (replace `default` with the desired namespace): + +```shell +kubectl label namespace default knative-eventing-injection=enabled +``` + +This should automatically create the `default` `Broker` in that namespace. + +```shell +kubectl -n default get broker default +``` + +Now create some function that wants to receive those events. + +## TODO + +Now create any triggers against that broker: + +## TODO + +### Implementation + +Broker and Trigger are intended to be black boxes. How they are implemented +should not matter to the end user. This section describes the specific +implementation that is currently in the repository. However, **the implmentation +may change at any time, absolutely no guarantees are made about the +implmentation**. + +#### Namespace + +Namespaces are reconciled by the +[Namespace Reconciler](../../pkg/reconciler/v1alpha1/namespace). The `Namespace +Reconciler` looks for all `namespace`s that have the label +`knative-eventing-injection: enabled`. If that label is present, then the +`Namespace Reconciler` reconciles: + +1. Creates the Broker Filter's `ServiceAccount`, `eventing-broker-filter`. +1. Ensures that `ServiceAccount` has the requisite RBAC permissions by giving + it the [`eventing-broker-filter`](../../config/200-broker-clusterrole.yaml) + `Role`. +1. Creates a `Broker` named `default`. + +#### Broker + +`Broker`s are reconciled by the +[Broker Reconciler](../../pkg/reconciler/v1alpha1/broker). For each `Broker`, it +reconciles: + +1. The 'everything' `Channel`. This is a `Channel` that all events in the + `Broker` are sent to. Anything that passes the `Broker`'s Ingress is sent to + this `Channel`. All `Trigger`s subscribe to this `Channel`. +1. The 'filter' `Deployment`. The `Deployment` runs + [cmd/broker/filter](../../cmd/broker/filter). Its purpose is the data plane + for all `Trigger`s related to this `Broker`. + - This piece is very similar to the existing Channel dispatchers, in that + all `Trigger`s for a given `Broker` route to this single `Deployment`. + The code inspects the Host header to determine which `Trigger` the + request is related to and then carries it out. + - Internally this binary uses the [pkg/broker](../../pkg/broker) library. +1. The 'filter' Kubernetes `Service`. This `Service` points to the 'filter' + `Deployment`. +1. The 'ingress' `Deployment`. The `Deployment` runs + [cmd/broker/ingress](../../cmd/broker/ingress). Its purpose is to inspect + all events that are entering the `Broker`. +1. The 'ingress' Kubernetes `Service`. This `Service` points to the 'ingress' + `Deployment`. This `Service`'s address is the address given for the + `Broker`. + +#### Trigger + +`Trigger`s are reconciled by the +[Trigger Reconciler](../../pkg/reconciler/v1alpha1/trigger). For each `Trigger`, +it reconciles: + +1. Determines the subscriber's URI. + - Currently uses the same logic as the `Subscription` Reconciler, so + supports Addressables and Kubernetes Services. +1. Creates a Kubernetes `Service` and Istio `VirtualService` pair. This allows + all Istio enabled `Pod`s to send to the `Trigger`'s address. + - This is the same as the current `Channel` implementation. The `Service` + points no where. The `VirtualService` reroutes requests that originally + went to the `Service`, to instead go to the `Broker`'s 'filter' + `Service`. +1. Creates `Subscription` from the `Broker`'s 'everything' `Channel` to the + `Trigger`'s Kubernetes `Service`. From 26586ab856a690a977b4de2b861f6e161189788e Mon Sep 17 00:00:00 2001 From: Adam Harwayne Date: Wed, 6 Mar 2019 15:41:26 -0800 Subject: [PATCH 125/221] Fill some of the usage section. --- docs/broker/README.md | 128 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 121 insertions(+), 7 deletions(-) diff --git a/docs/broker/README.md b/docs/broker/README.md index 5f5e2e35b41..f3709d669d8 100644 --- a/docs/broker/README.md +++ b/docs/broker/README.md @@ -51,7 +51,10 @@ spec: ## Usage -The easiest way to get started, is to annotate your namespace (replace `default` with the desired namespace): +### Annotation + +The easiest way to get started, is to annotate your namespace (replace `default` +with the desired namespace): ```shell kubectl label namespace default knative-eventing-injection=enabled @@ -63,13 +66,124 @@ This should automatically create the `default` `Broker` in that namespace. kubectl -n default get broker default ``` -Now create some function that wants to receive those events. +### Subscriber + +Now create some function that wants to receive those events. This document will +assume the following, but it could be anything that is `Addressable`. + +```yaml +apiVersion: serving.knative.dev/v1alpha1 +kind: Service +metadata: + name: my-service + namespace: default +spec: + runLatest: + configuration: + revisionTemplate: + spec: + container: + # This corresponds to + # https://github.com/knative/eventing-sources/blob/v0.2.1/cmd/message_dumper/dumper.go. + image: gcr.io/knative-releases/github.com/knative/eventing-sources/cmd/message_dumper@sha256:ab5391755f11a5821e7263686564b3c3cd5348522f5b31509963afb269ddcd63 +``` -## TODO +### Trigger -Now create any triggers against that broker: +Create a `Trigger` that sends only events of a particular type to `my-service`: -## TODO +```yaml +apiVersion: eventing.knative.dev/v1alpha1 +kind: Trigger +metadata: + name: my-service-trigger + namespace: default +spec: + filter: + sourceAndType: + type: dev.knative.foo.bar + subscriber: + ref: + apiVersion: serving.knative.dev/v1alpha1 + kind: Service + name: my-service +``` + +#### Defaulting + +The Webhook will default certain unspecified fields. For example if +`spec.broker` is unspecified, it will default to `default`. If +`spec.filter.sourceAndType.type` or `spec.filter.sourceAndType.Source` are +unspecified, then they will default to the special value `Any`, which matches +everything. + +The Webhook will default the YAML above to: + +```yaml +apiVersion: eventing.knative.dev/v1alpha1 +kind: Trigger +metadata: + name: my-service-trigger + namespace: default +spec: + broker: default # Defaulted by the Webhook. + filter: + sourceAndType: + type: dev.knative.foo.bar + source: Any # Defaulted by the Webhook. + subscriber: + ref: + apiVersion: serving.knative.dev/v1alpha1 + kind: Service + name: my-service +``` + +You can make multiple `Trigger`s on the same `Broker` corresponding to different +types, sources, and subscribers. + +### Source + +Now have something emit an event of the correct type (`dev.knative.foo.bar`) +into the `Broker`. We can either do this manually or with a normal Knative +Source. + +#### Manual + +The `Broker`'s address is well known, it will always be +`-broker..svc.`. In our case, it is +`default-broker.default.svc.cluster.local`. + +While SSHed into a `Pod` with the Istio sidecar, run: + +```shell +curl -v "http://default-broker.default.svc.cluster.local/" \ + -X POST \ + -H "X-B3-Flags: 1" \ + -H "CE-CloudEventsVersion: 0.1" \ + -H "CE-EventType: dev.knative.foo.bar" \ + -H "CE-EventTime: 2018-04-05T03:56:24Z" \ + -H "CE-EventID: 45a8b444-3213-4758-be3f-540bf93f85ff" \ + -H "CE-Source: dev.knative.example" \ + -H 'Content-Type: application/json' \ + -d '{ "much": "wow" }' +``` + +#### Knative Source + +Provide the Knative Source the `default` `Broker` as its sink: + +```yaml +apiVersion: sources.eventing.knative.dev/v1alpha1 +kind: ContainerSource +metadata: + name: heartbeats-sender +spec: + image: github.com/knative/eventing-sources/cmd/heartbeats/ + sink: + apiVersion: eventing.knative.dev/v1alpha1 + kind: Broker + name: default +``` ### Implementation @@ -127,11 +241,11 @@ it reconciles: 1. Determines the subscriber's URI. - Currently uses the same logic as the `Subscription` Reconciler, so - supports Addressables and Kubernetes Services. + supports Addressables and Kubernetes `Service`s. 1. Creates a Kubernetes `Service` and Istio `VirtualService` pair. This allows all Istio enabled `Pod`s to send to the `Trigger`'s address. - This is the same as the current `Channel` implementation. The `Service` - points no where. The `VirtualService` reroutes requests that originally + points nowhere. The `VirtualService` reroutes requests that originally went to the `Service`, to instead go to the `Broker`'s 'filter' `Service`. 1. Creates `Subscription` from the `Broker`'s 'everything' `Channel` to the From a3e485f5c80f232a3c0d5654bed2269f8b153de2 Mon Sep 17 00:00:00 2001 From: Adam Harwayne Date: Thu, 7 Mar 2019 14:39:45 -0800 Subject: [PATCH 126/221] Add instructions for installing the Broker without using Namespace annotation. --- docs/broker/README.md | 47 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/docs/broker/README.md b/docs/broker/README.md index f3709d669d8..4b991a83836 100644 --- a/docs/broker/README.md +++ b/docs/broker/README.md @@ -51,7 +51,13 @@ spec: ## Usage -### Annotation +### Broker + +There are two ways to create a Broker, via [namespace annotation](#annotation) or [manual setup](#manual-setup). + +Normally the [namespace annotation](#annotation) is used to do this setup. + +#### Annotation The easiest way to get started, is to annotate your namespace (replace `default` with the desired namespace): @@ -66,6 +72,45 @@ This should automatically create the `default` `Broker` in that namespace. kubectl -n default get broker default ``` +#### Manual Setup + +In order to setup a `Broker` manually, we must first create the required +`ServiceAccount` and give it the proper RBAC permissions. This setup is required +once per namespace. These instructions will use the `default` namespace, but you +can replace it with any namespace you want to install a `Broker` into. + +Create the `ServiceAccount`. + +```shell +kubectl -n default create serviceaccount eventing-broker-filter +``` + +Then give it the needed RBAC permissions: + +```shell +kubectl -n default create rolebinding eventing-broker-filter \ + --clusterrole=eventing-broker-filter \ + --user=eventing-broker-filter +``` + +Note that the previous commands uses three different objects, all named +`eventing-broker-filter`. The `ClusterRole` is installed with Knative Eventing +[here](../../config/200-broker-clusterrole.yaml). The `ServiceAccount` was +created two commands prior. The `RoleBinding` is created with this command. + +Now we can create the `Broker`. Note that this example uses the name `default`, +but could be replaced by any other valid name. + +```shell +cat << EOF | kubectl apply -f - +apiVersion: eventing.knative.dev/v1alpha1 +kind: Broker +metadata: + namespace: default + name: default +EOF +``` + ### Subscriber Now create some function that wants to receive those events. This document will From a3672062ce8c9b31e71789b5d21da1eade302546 Mon Sep 17 00:00:00 2001 From: Adam Harwayne Date: Thu, 7 Mar 2019 17:30:40 -0800 Subject: [PATCH 127/221] Create example_{brokers,triggers}.yaml to document how they can be used. --- b.yaml | 11 --- b2.yaml | 5 -- docs/broker/example_brokers.yaml | 44 ++++++++++ docs/broker/example_triggers.yaml | 129 ++++++++++++++++++++++++++++++ t.yaml | 11 --- t2.yaml | 16 ---- t3.yaml | 16 ---- t4.yaml | 11 --- 8 files changed, 173 insertions(+), 70 deletions(-) delete mode 100644 b.yaml delete mode 100644 b2.yaml create mode 100644 docs/broker/example_brokers.yaml create mode 100644 docs/broker/example_triggers.yaml delete mode 100644 t.yaml delete mode 100644 t2.yaml delete mode 100644 t3.yaml delete mode 100644 t4.yaml diff --git a/b.yaml b/b.yaml deleted file mode 100644 index 595b6eb20ac..00000000000 --- a/b.yaml +++ /dev/null @@ -1,11 +0,0 @@ -apiVersion: eventing.knative.dev/v1alpha1 -kind: Broker -metadata: - name: default -spec: - channelTemplate: - provisioner: - apiVersion: eventing.knative.dev/v1alpha1 - kind: ClusterChannelProvisioner - name: gcp-pubsub - diff --git a/b2.yaml b/b2.yaml deleted file mode 100644 index 1c0f7b43a82..00000000000 --- a/b2.yaml +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: eventing.knative.dev/v1alpha1 -kind: Broker -metadata: - name: default -spec: {} diff --git a/docs/broker/example_brokers.yaml b/docs/broker/example_brokers.yaml new file mode 100644 index 00000000000..d1cd9090fcb --- /dev/null +++ b/docs/broker/example_brokers.yaml @@ -0,0 +1,44 @@ +# Copyright 2018 The Knative Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This file is a list of example Brokers. Each could be used independently. + +--- + +# By not specifying a spec, the default Channel for the namespace will be used. + +apiVersion: eventing.knative.dev/v1alpha1 +kind: Broker +metadata: + name: default-channel + +--- + +# By specifying spec.channelTemplate, we guarantee the Channel implementation +# used, and thus guarantee the durability of the events that are sent to this +# Broker. + +apiVersion: eventing.knative.dev/v1alpha1 +kind: Broker +metadata: + name: pubsub-channel +spec: + channelTemplate: + provisioner: + apiVersion: eventing.knative.dev/v1alpha1 + kind: ClusterChannelProvisioner + name: gcp-pubsub + + + diff --git a/docs/broker/example_triggers.yaml b/docs/broker/example_triggers.yaml new file mode 100644 index 00000000000..af52fd4d9a2 --- /dev/null +++ b/docs/broker/example_triggers.yaml @@ -0,0 +1,129 @@ +# Copyright 2018 The Knative Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This file is a list of example Triggers. Each could be used independently. + +--- + +# By not specifying spec.broker, this Trigger will associate with the Broker +# named 'default'. In addition, by not specifying spec.filter, this Trigger +# will match all events sent through the Broker. + +apiVersion: eventing.knative.dev/v1alpha1 +kind: Trigger +metadata: + name: knative-service-default-broker +spec: + subscriber: + ref: + apiVersion: serving.knative.dev/v1alpha1 + kind: Service + name: message-dumper + +--- + +# K8s Service is also a valid Subscriber. + +apiVersion: eventing.knative.dev/v1alpha1 +kind: Trigger +metadata: + name: k8s-service-default-broker +spec: + subscriber: + ref: + apiVersion: v1 + kind: Service + name: message-dumper + +--- + +# By specifying spec.broker, this Trigger will match events sent through the +# 'my-other-broker' Broker (instead of the 'default' Broker). + +apiVersion: eventing.knative.dev/v1alpha1 +kind: Trigger +metadata: + name: knative-service-my-other-broker +spec: + broker: my-other-broker + subscriber: + ref: + apiVersion: serving.knative.dev/v1alpha1 + kind: Service + name: message-dumper + +--- + +# We can filter on either the event's type, source, or both. The special value +# 'Any' matches everything. If either is not specified, it defaults to 'Any'. + +--- + +# This Trigger matches all events of type 'dev.knative.foo', regardless of +# source, that are sent to the 'default' Broker. + +apiVersion: eventing.knative.dev/v1alpha1 +kind: Trigger +metadata: + name: filtering-type +spec: + filter: + sourceAndType: + type: dev.knative.foo + subscriber: + ref: + apiVersion: serving.knative.dev/v1alpha1 + kind: Service + name: message-dumper + +--- + +# This Trigger matches all events of source 'dev.knative.bar', regardless of +# type, that are sent to the 'default' Broker. + +apiVersion: eventing.knative.dev/v1alpha1 +kind: Trigger +metadata: + name: filtering-source +spec: + filter: + sourceAndType: + source: dev.knative.bar + # The Webhook will default this in, but it does not hurt to specify it. + type: Any + subscriber: + ref: + apiVersion: serving.knative.dev/v1alpha1 + kind: Service + name: message-dumper + +--- + +# This Trigger matches all events of type 'dev.knative.foo' and source +# 'dev.knative.bar', that are sent to the 'default' Broker. + +apiVersion: eventing.knative.dev/v1alpha1 +kind: Trigger +metadata: + name: filtering-type-and-source +spec: + filter: + sourceAndType: + type: dev.knative.foo + source: dev.knative.bar + subscriber: + ref: + apiVersion: serving.knative.dev/v1alpha1 + kind: Service + name: message-dumper diff --git a/t.yaml b/t.yaml deleted file mode 100644 index 0e2604dd595..00000000000 --- a/t.yaml +++ /dev/null @@ -1,11 +0,0 @@ -apiVersion: eventing.knative.dev/v1alpha1 -kind: Trigger -metadata: - name: t -spec: - subscriber: - ref: - apiVersion: serving.knative.dev/v1alpha1 - kind: Service - name: message-dumper - diff --git a/t2.yaml b/t2.yaml deleted file mode 100644 index 105b912796e..00000000000 --- a/t2.yaml +++ /dev/null @@ -1,16 +0,0 @@ -apiVersion: eventing.knative.dev/v1alpha1 -kind: Trigger -metadata: - name: t -spec: - # Our Cloud Event parsing library seems to have a bug and forces to put type and source in double - # quotes (as it thinks the actual value is `"foo"`, not `foo`). - filter: - sourceAndType: - type: '"com.example.someevent"' - source: '"/mycontext/subcontext"' - subscriber: - ref: - apiVersion: serving.knative.dev/v1alpha1 - kind: Service - name: message-dumper diff --git a/t3.yaml b/t3.yaml deleted file mode 100644 index 0ea783d5675..00000000000 --- a/t3.yaml +++ /dev/null @@ -1,16 +0,0 @@ -apiVersion: eventing.knative.dev/v1alpha1 -kind: Trigger -metadata: - name: t -spec: - # Our Cloud Event parsing library seems to have a bug and forces to put type and source in double - # quotes (as it thinks the actual value is `"foo"`, not `foo`). - filter: - sourceAndType: - type: '"com.example.someevent"' - source: '"/mycontext/subcontext"' - subscriber: - ref: - apiVersion: v1 - kind: Service - name: svc diff --git a/t4.yaml b/t4.yaml deleted file mode 100644 index a6a981bfc0b..00000000000 --- a/t4.yaml +++ /dev/null @@ -1,11 +0,0 @@ -apiVersion: eventing.knative.dev/v1alpha1 -kind: Trigger -metadata: - name: t -spec: - subscriber: - ref: - apiVersion: v1 - kind: Service - name: svc - From a0599d649c38bb206faa0bcbe7df5ce12afb1a35 Mon Sep 17 00:00:00 2001 From: Adam Harwayne Date: Thu, 7 Mar 2019 19:11:06 -0800 Subject: [PATCH 128/221] Fix MD linter issues. --- docs/broker/README.md | 86 +++++++++++++++++++++---------------------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/docs/broker/README.md b/docs/broker/README.md index 4b991a83836..67b7c9bc21c 100644 --- a/docs/broker/README.md +++ b/docs/broker/README.md @@ -1,9 +1,9 @@ -## Broker and Trigger CRDs +# Broker and Trigger CRDs The Broker and Trigger CRDs, both in `eventing.knative.dev/v1alpha1`, are interdependent. -#### Broker +## Broker Broker represents an 'event mesh'. Events are sent to the Broker's ingress and are then sent to any subscribers that are interested in that event. Once inside @@ -26,7 +26,7 @@ spec: name: gcp-pubsub ``` -#### Trigger +## Trigger Trigger represents a desire to subscribe to events from a specific Broker. Basic filtering on the types of events is provided. @@ -230,7 +230,7 @@ spec: name: default ``` -### Implementation +## Implementation Broker and Trigger are intended to be black boxes. How they are implemented should not matter to the end user. This section describes the specific @@ -238,7 +238,7 @@ implementation that is currently in the repository. However, **the implmentation may change at any time, absolutely no guarantees are made about the implmentation**. -#### Namespace +### Namespace Namespaces are reconciled by the [Namespace Reconciler](../../pkg/reconciler/v1alpha1/namespace). The `Namespace @@ -246,52 +246,52 @@ Reconciler` looks for all `namespace`s that have the label `knative-eventing-injection: enabled`. If that label is present, then the `Namespace Reconciler` reconciles: -1. Creates the Broker Filter's `ServiceAccount`, `eventing-broker-filter`. -1. Ensures that `ServiceAccount` has the requisite RBAC permissions by giving - it the [`eventing-broker-filter`](../../config/200-broker-clusterrole.yaml) - `Role`. -1. Creates a `Broker` named `default`. +1. Creates the Broker Filter's `ServiceAccount`, `eventing-broker-filter`. +1. Ensures that `ServiceAccount` has the requisite RBAC permissions by giving + it the [`eventing-broker-filter`](../../config/200-broker-clusterrole.yaml) + `Role`. +1. Creates a `Broker` named `default`. -#### Broker +### Broker `Broker`s are reconciled by the [Broker Reconciler](../../pkg/reconciler/v1alpha1/broker). For each `Broker`, it reconciles: -1. The 'everything' `Channel`. This is a `Channel` that all events in the - `Broker` are sent to. Anything that passes the `Broker`'s Ingress is sent to - this `Channel`. All `Trigger`s subscribe to this `Channel`. -1. The 'filter' `Deployment`. The `Deployment` runs - [cmd/broker/filter](../../cmd/broker/filter). Its purpose is the data plane - for all `Trigger`s related to this `Broker`. - - This piece is very similar to the existing Channel dispatchers, in that - all `Trigger`s for a given `Broker` route to this single `Deployment`. - The code inspects the Host header to determine which `Trigger` the - request is related to and then carries it out. - - Internally this binary uses the [pkg/broker](../../pkg/broker) library. -1. The 'filter' Kubernetes `Service`. This `Service` points to the 'filter' - `Deployment`. -1. The 'ingress' `Deployment`. The `Deployment` runs - [cmd/broker/ingress](../../cmd/broker/ingress). Its purpose is to inspect - all events that are entering the `Broker`. -1. The 'ingress' Kubernetes `Service`. This `Service` points to the 'ingress' - `Deployment`. This `Service`'s address is the address given for the - `Broker`. - -#### Trigger +1. The 'everything' `Channel`. This is a `Channel` that all events in the + `Broker` are sent to. Anything that passes the `Broker`'s Ingress is sent to + this `Channel`. All `Trigger`s subscribe to this `Channel`. +1. The 'filter' `Deployment`. The `Deployment` runs + [cmd/broker/filter](../../cmd/broker/filter). Its purpose is the data plane + for all `Trigger`s related to this `Broker`. + - This piece is very similar to the existing Channel dispatchers, in that + all `Trigger`s for a given `Broker` route to this single `Deployment`. + The code inspects the Host header to determine which `Trigger` the + request is related to and then carries it out. + - Internally this binary uses the [pkg/broker](../../pkg/broker) library. +1. The 'filter' Kubernetes `Service`. This `Service` points to the 'filter' + `Deployment`. +1. The 'ingress' `Deployment`. The `Deployment` runs + [cmd/broker/ingress](../../cmd/broker/ingress). Its purpose is to inspect + all events that are entering the `Broker`. +1. The 'ingress' Kubernetes `Service`. This `Service` points to the 'ingress' + `Deployment`. This `Service`'s address is the address given for the + `Broker`. + +### Trigger `Trigger`s are reconciled by the [Trigger Reconciler](../../pkg/reconciler/v1alpha1/trigger). For each `Trigger`, it reconciles: -1. Determines the subscriber's URI. - - Currently uses the same logic as the `Subscription` Reconciler, so - supports Addressables and Kubernetes `Service`s. -1. Creates a Kubernetes `Service` and Istio `VirtualService` pair. This allows - all Istio enabled `Pod`s to send to the `Trigger`'s address. - - This is the same as the current `Channel` implementation. The `Service` - points nowhere. The `VirtualService` reroutes requests that originally - went to the `Service`, to instead go to the `Broker`'s 'filter' - `Service`. -1. Creates `Subscription` from the `Broker`'s 'everything' `Channel` to the - `Trigger`'s Kubernetes `Service`. +1. Determines the subscriber's URI. + - Currently uses the same logic as the `Subscription` Reconciler, so + supports Addressables and Kubernetes `Service`s. +1. Creates a Kubernetes `Service` and Istio `VirtualService` pair. This allows + all Istio enabled `Pod`s to send to the `Trigger`'s address. + - This is the same as the current `Channel` implementation. The `Service` + points nowhere. The `VirtualService` reroutes requests that originally + went to the `Service`, to instead go to the `Broker`'s 'filter' + `Service`. +1. Creates `Subscription` from the `Broker`'s 'everything' `Channel` to the + `Trigger`'s Kubernetes `Service`. From 31f5e525d116314a50e8f01b452840400f87c472 Mon Sep 17 00:00:00 2001 From: Adam Harwayne Date: Thu, 7 Mar 2019 20:22:29 -0800 Subject: [PATCH 129/221] Fix MD linter issues. --- docs/broker/README.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/broker/README.md b/docs/broker/README.md index 67b7c9bc21c..fdfc4404e90 100644 --- a/docs/broker/README.md +++ b/docs/broker/README.md @@ -264,11 +264,11 @@ reconciles: 1. The 'filter' `Deployment`. The `Deployment` runs [cmd/broker/filter](../../cmd/broker/filter). Its purpose is the data plane for all `Trigger`s related to this `Broker`. - - This piece is very similar to the existing Channel dispatchers, in that - all `Trigger`s for a given `Broker` route to this single `Deployment`. - The code inspects the Host header to determine which `Trigger` the - request is related to and then carries it out. - - Internally this binary uses the [pkg/broker](../../pkg/broker) library. + - This piece is very similar to the existing Channel dispatchers, in that + all `Trigger`s for a given `Broker` route to this single `Deployment`. + The code inspects the Host header to determine which `Trigger` the + request is related to and then carries it out. + - Internally this binary uses the [pkg/broker](../../pkg/broker) library. 1. The 'filter' Kubernetes `Service`. This `Service` points to the 'filter' `Deployment`. 1. The 'ingress' `Deployment`. The `Deployment` runs @@ -285,13 +285,13 @@ reconciles: it reconciles: 1. Determines the subscriber's URI. - - Currently uses the same logic as the `Subscription` Reconciler, so - supports Addressables and Kubernetes `Service`s. + - Currently uses the same logic as the `Subscription` Reconciler, so + supports Addressables and Kubernetes `Service`s. 1. Creates a Kubernetes `Service` and Istio `VirtualService` pair. This allows all Istio enabled `Pod`s to send to the `Trigger`'s address. - - This is the same as the current `Channel` implementation. The `Service` - points nowhere. The `VirtualService` reroutes requests that originally - went to the `Service`, to instead go to the `Broker`'s 'filter' - `Service`. + - This is the same as the current `Channel` implementation. The `Service` + points nowhere. The `VirtualService` reroutes requests that originally + went to the `Service`, to instead go to the `Broker`'s 'filter' + `Service`. 1. Creates `Subscription` from the `Broker`'s 'everything' `Channel` to the `Trigger`'s Kubernetes `Service`. From ac179cdec8b6028a5468b5a9c746479c6bdf4b22 Mon Sep 17 00:00:00 2001 From: Adam Harwayne Date: Thu, 7 Mar 2019 20:37:43 -0800 Subject: [PATCH 130/221] Fix MD linter issues. --- docs/broker/README.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/broker/README.md b/docs/broker/README.md index fdfc4404e90..0ba25b67ec6 100644 --- a/docs/broker/README.md +++ b/docs/broker/README.md @@ -264,11 +264,11 @@ reconciles: 1. The 'filter' `Deployment`. The `Deployment` runs [cmd/broker/filter](../../cmd/broker/filter). Its purpose is the data plane for all `Trigger`s related to this `Broker`. - - This piece is very similar to the existing Channel dispatchers, in that - all `Trigger`s for a given `Broker` route to this single `Deployment`. - The code inspects the Host header to determine which `Trigger` the - request is related to and then carries it out. - - Internally this binary uses the [pkg/broker](../../pkg/broker) library. + - This piece is very similar to the existing Channel dispatchers, in that + all `Trigger`s for a given `Broker` route to this single `Deployment`. + The code inspects the Host header to determine which `Trigger` the + request is related to and then carries it out. + - Internally this binary uses the [pkg/broker](../../pkg/broker) library. 1. The 'filter' Kubernetes `Service`. This `Service` points to the 'filter' `Deployment`. 1. The 'ingress' `Deployment`. The `Deployment` runs @@ -285,13 +285,13 @@ reconciles: it reconciles: 1. Determines the subscriber's URI. - - Currently uses the same logic as the `Subscription` Reconciler, so - supports Addressables and Kubernetes `Service`s. + - Currently uses the same logic as the `Subscription` Reconciler, so + supports Addressables and Kubernetes `Service`s. 1. Creates a Kubernetes `Service` and Istio `VirtualService` pair. This allows all Istio enabled `Pod`s to send to the `Trigger`'s address. - - This is the same as the current `Channel` implementation. The `Service` - points nowhere. The `VirtualService` reroutes requests that originally - went to the `Service`, to instead go to the `Broker`'s 'filter' - `Service`. + - This is the same as the current `Channel` implementation. The `Service` + points nowhere. The `VirtualService` reroutes requests that originally + went to the `Service`, to instead go to the `Broker`'s 'filter' + `Service`. 1. Creates `Subscription` from the `Broker`'s 'everything' `Channel` to the `Trigger`'s Kubernetes `Service`. From dfa159f228be42760fa71fe451fbc6255a4cc6c2 Mon Sep 17 00:00:00 2001 From: Adam Harwayne Date: Thu, 7 Mar 2019 21:25:37 -0800 Subject: [PATCH 131/221] Minor clean up. --- config/300-broker.yaml | 1 + config/300-trigger.yaml | 1 + pkg/apis/eventing/v1alpha1/broker_defaults.go | 8 ++------ 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/config/300-broker.yaml b/config/300-broker.yaml index ce0421a7b66..bb74cb7dd3f 100644 --- a/config/300-broker.yaml +++ b/config/300-broker.yaml @@ -11,6 +11,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. + apiVersion: apiextensions.k8s.io/v1beta1 kind: CustomResourceDefinition metadata: diff --git a/config/300-trigger.yaml b/config/300-trigger.yaml index 5ca0c8beb24..122cdba1d67 100644 --- a/config/300-trigger.yaml +++ b/config/300-trigger.yaml @@ -11,6 +11,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. + apiVersion: apiextensions.k8s.io/v1beta1 kind: CustomResourceDefinition metadata: diff --git a/pkg/apis/eventing/v1alpha1/broker_defaults.go b/pkg/apis/eventing/v1alpha1/broker_defaults.go index 2efdd4e3f79..54df6bed298 100644 --- a/pkg/apis/eventing/v1alpha1/broker_defaults.go +++ b/pkg/apis/eventing/v1alpha1/broker_defaults.go @@ -16,14 +16,10 @@ limitations under the License. package v1alpha1 -const ( - brokerLabel = "eventing.knative.dev/broker" -) - func (b *Broker) SetDefaults() { - b.Spec.SetDefaults(b.Name) + b.Spec.SetDefaults() } -func (bs *BrokerSpec) SetDefaults(brokerName string) { +func (bs *BrokerSpec) SetDefaults() { // None } From 3c0915ffed195577d47568d7a4c84ca005e5e7e9 Mon Sep 17 00:00:00 2001 From: nachocano Date: Fri, 8 Mar 2019 15:02:35 -0800 Subject: [PATCH 132/221] adding type as authoritative --- Gopkg.lock | 1 + config/300-eventtype.yaml | 3 +++ e.yaml => docs/registry/example_eventtype.yaml | 5 ++++- e1.yaml | 8 -------- pkg/apis/eventing/v1alpha1/eventtype_types.go | 3 ++- pkg/apis/eventing/v1alpha1/eventtype_validation.go | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) rename e.yaml => docs/registry/example_eventtype.yaml (57%) delete mode 100644 e1.yaml diff --git a/Gopkg.lock b/Gopkg.lock index 0cbc9bc008a..0edd1755782 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -1249,6 +1249,7 @@ "github.com/Shopify/sarama", "github.com/bsm/sarama-cluster", "github.com/cloudevents/sdk-go/pkg/cloudevents", + "github.com/cloudevents/sdk-go/pkg/cloudevents/types", "github.com/fsnotify/fsnotify", "github.com/golang/glog", "github.com/google/go-cmp/cmp", diff --git a/config/300-eventtype.yaml b/config/300-eventtype.yaml index b49cc7ea5a1..20857975c88 100644 --- a/config/300-eventtype.yaml +++ b/config/300-eventtype.yaml @@ -30,6 +30,9 @@ spec: subresources: status: {} additionalPrinterColumns: + - name: Type + type: string + JSONPath: ".spec.type" - name: Source type: string JSONPath: ".spec.source" diff --git a/e.yaml b/docs/registry/example_eventtype.yaml similarity index 57% rename from e.yaml rename to docs/registry/example_eventtype.yaml index 66efcaf7634..1e736dea0ee 100644 --- a/e.yaml +++ b/docs/registry/example_eventtype.yaml @@ -1,8 +1,11 @@ apiVersion: eventing.knative.dev/v1alpha1 kind: EventType metadata: + # advisory name: com.github.pullrequest spec: + # authoritative + type: dev.knative.source.github.pull_request + # cloud event source or knative source? source: github.com schema: http://foo2.example/schema - diff --git a/e1.yaml b/e1.yaml deleted file mode 100644 index 65e25cffa27..00000000000 --- a/e1.yaml +++ /dev/null @@ -1,8 +0,0 @@ -apiVersion: eventing.knative.dev/v1alpha1 -kind: EventType -metadata: - name: dev.knative.source.bitbucket.pullrequest:created -spec: - source: https://api.bitbucket.org/api/2.0/pullrequests/pullrequest_id - schema: http://foo2.example/schema - diff --git a/pkg/apis/eventing/v1alpha1/eventtype_types.go b/pkg/apis/eventing/v1alpha1/eventtype_types.go index bb9b77ed972..68499c2fc62 100644 --- a/pkg/apis/eventing/v1alpha1/eventtype_types.go +++ b/pkg/apis/eventing/v1alpha1/eventtype_types.go @@ -58,7 +58,8 @@ type EventTypeSpec struct { // +optional DeprecatedGeneration int64 `json:"generation,omitempty"` - // TODO this should probably need to be updated + // TODO these attributes should be updated once we clarify the UX. + Type string `json:"type,omitempty"` Source string `json:"source,omitempty"` // +optional Schema string `json:"schema,omitempty"` diff --git a/pkg/apis/eventing/v1alpha1/eventtype_validation.go b/pkg/apis/eventing/v1alpha1/eventtype_validation.go index d22f771baa6..2f4419ef089 100644 --- a/pkg/apis/eventing/v1alpha1/eventtype_validation.go +++ b/pkg/apis/eventing/v1alpha1/eventtype_validation.go @@ -41,7 +41,7 @@ func (r *EventType) CheckImmutableFields(og apis.Immutable) *apis.FieldError { } // TODO check other fields. - if diff := cmp.Diff(original.Spec.Source, r.Spec.Source); diff != "" { + if diff := cmp.Diff(original.Spec.Type, r.Spec.Type); diff != "" { return &apis.FieldError{ Message: "Immutable fields changed (-old +new)", Paths: []string{"spec", "events"}, From 858f00e6738b07292f7f96c4d91a3fc9b3f6cf26 Mon Sep 17 00:00:00 2001 From: nachocano Date: Fri, 8 Mar 2019 15:26:15 -0800 Subject: [PATCH 133/221] Should actually compare to lowercase --- cmd/broker/ingress/main.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/broker/ingress/main.go b/cmd/broker/ingress/main.go index 2a29d9a2499..b3c08f30621 100644 --- a/cmd/broker/ingress/main.go +++ b/cmd/broker/ingress/main.go @@ -49,9 +49,9 @@ const ( v1EventId = "Ce-Eventid" v1EventType = "Ce-Eventtype" v1EventSource = "Ce-Source" - v2EventId = "ce-id" - v2EventType = "ce-type" - v2EventSource = "ce-source" + v2EventId = "Ce-Id" + v2EventType = "Ce-Type" + v2EventSource = "Ce-Source" ) var ( From 3e2291a56871fa86563f8bc08371bbf2a87f48f0 Mon Sep 17 00:00:00 2001 From: nachocano Date: Fri, 8 Mar 2019 16:00:52 -0800 Subject: [PATCH 134/221] listing all event types... we should use some sort of selectors. label selectors won't work on spec.type as they may not conform to the label format. field selectors doesn't seem to work for CRDs beyond metadata.name and namespace. --- cmd/broker/ingress/main.go | 2 +- pkg/broker/ingress.go | 56 +++++++++++++++++++++----------------- 2 files changed, 32 insertions(+), 26 deletions(-) diff --git a/cmd/broker/ingress/main.go b/cmd/broker/ingress/main.go index b3c08f30621..33fdecf75bf 100644 --- a/cmd/broker/ingress/main.go +++ b/cmd/broker/ingress/main.go @@ -140,7 +140,7 @@ func NewHandler(logger *zap.Logger, destination, policy string, client client.Cl handler := &Handler{ logger: logger, dispatcher: provisioners.NewMessageDispatcher(logger.Sugar()), - ingressPolicy: broker.NewIngressPolicy(logger.Sugar(), client, policy), + ingressPolicy: broker.NewIngressPolicy(client, policy), destination: fmt.Sprintf("http://%s", destination), client: client, } diff --git a/pkg/broker/ingress.go b/pkg/broker/ingress.go index c423ec6ffa3..f42e14231bb 100644 --- a/pkg/broker/ingress.go +++ b/pkg/broker/ingress.go @@ -22,9 +22,7 @@ import ( "github.com/cloudevents/sdk-go/pkg/cloudevents" eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" - "go.uber.org/zap" - k8serrors "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/types" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/client" ) @@ -40,19 +38,17 @@ type IngressPolicy interface { type AllowAnyPolicy struct{} type AllowRegisteredPolicy struct { - logger *zap.SugaredLogger client client.Client } -func NewIngressPolicy(logger *zap.SugaredLogger, client client.Client, policy string) IngressPolicy { - return newIngressPolicy(logger, client, policy) +func NewIngressPolicy(client client.Client, policy string) IngressPolicy { + return newIngressPolicy(client, policy) } -func newIngressPolicy(logger *zap.SugaredLogger, client client.Client, policy string) IngressPolicy { +func newIngressPolicy(client client.Client, policy string) IngressPolicy { switch policy { case allowRegisteredTypes: return &AllowRegisteredPolicy{ - logger: logger, client: client, } case allowAny: @@ -62,27 +58,37 @@ func newIngressPolicy(logger *zap.SugaredLogger, client client.Client, policy st } } -func (policy *AllowAnyPolicy) AllowEvent(namespace string, event *cloudevents.Event) bool { +func (p *AllowAnyPolicy) AllowEvent(namespace string, event *cloudevents.Event) bool { return true } -func (policy *AllowRegisteredPolicy) AllowEvent(namespace string, event *cloudevents.Event) bool { - et := &eventingv1alpha1.EventType{} - name := event.Type() +func (p *AllowRegisteredPolicy) AllowEvent(namespace string, event *cloudevents.Event) bool { + opts := &client.ListOptions{ + Namespace: namespace, + // Set Raw because if we need to get more than one page, then we will put the continue token + // into opts.Raw.Continue. + Raw: &metav1.ListOptions{}, + } - err := policy.client.Get(context.TODO(), - types.NamespacedName{ - Namespace: namespace, - Name: name, - }, - et) + ctx := context.TODO() - if k8serrors.IsNotFound(err) { - policy.logger.Warnf("EventType not found: %q", name) - return false - } else if err != nil { - policy.logger.Errorf("Error getting EventType: %q, %v", name, err) - return false + // TODO this is very inefficient, we need to somehow select with a fieldSelector on spec.type, + // but it is not supported. + for { + el := &eventingv1alpha1.EventTypeList{} + err := p.client.List(ctx, opts, el) + if err != nil { + return false + } + for _, e := range el.Items { + if e.Spec.Type == event.Type() { + return true + } + } + if el.Continue != "" { + opts.Raw.Continue = el.Continue + } else { + return false + } } - return true } From 4d168c6a2c5544977d97faeff49e6fef1cf75957 Mon Sep 17 00:00:00 2001 From: nachocano Date: Mon, 11 Mar 2019 13:49:01 -0700 Subject: [PATCH 135/221] Might not need origin after all, but adding it here --- pkg/apis/eventing/v1alpha1/eventtype_types.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pkg/apis/eventing/v1alpha1/eventtype_types.go b/pkg/apis/eventing/v1alpha1/eventtype_types.go index 68499c2fc62..174b0a78458 100644 --- a/pkg/apis/eventing/v1alpha1/eventtype_types.go +++ b/pkg/apis/eventing/v1alpha1/eventtype_types.go @@ -59,9 +59,12 @@ type EventTypeSpec struct { DeprecatedGeneration int64 `json:"generation,omitempty"` // TODO these attributes should be updated once we clarify the UX. + // Type and Source refer to the cloud event type and source. Type string `json:"type,omitempty"` Source string `json:"source,omitempty"` // +optional + Origin string `json:"origin,omitempty"` + // +optional Schema string `json:"schema,omitempty"` } From edbed928d017a066271673d25da9188054afbfd8 Mon Sep 17 00:00:00 2001 From: nachocano Date: Mon, 11 Mar 2019 14:00:18 -0700 Subject: [PATCH 136/221] adding origin to yaml as well --- config/300-eventtype.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/config/300-eventtype.yaml b/config/300-eventtype.yaml index 20857975c88..d9ab40eda87 100644 --- a/config/300-eventtype.yaml +++ b/config/300-eventtype.yaml @@ -36,6 +36,9 @@ spec: - name: Source type: string JSONPath: ".spec.source" + - name: Origin + type: string + JSONPath: ".spec.origin" - name: Schema type: string JSONPath: ".spec.schema" From a0c0729036bfa46f9ff423d75faecd0673778e4a Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Mon, 11 Mar 2019 18:02:42 -0700 Subject: [PATCH 137/221] eventtypes instead of event-types to maintain consistency. --- config/300-eventtype.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/config/300-eventtype.yaml b/config/300-eventtype.yaml index d9ab40eda87..5f6c4bc2b64 100644 --- a/config/300-eventtype.yaml +++ b/config/300-eventtype.yaml @@ -14,14 +14,14 @@ apiVersion: apiextensions.k8s.io/v1beta1 kind: CustomResourceDefinition metadata: - name: event-types.eventing.knative.dev + name: eventtypes.eventing.knative.dev spec: group: eventing.knative.dev version: v1alpha1 names: kind: EventType - plural: event-types - singular: event-type + plural: eventtypes + singular: eventtype categories: - all - knative From 30f9031d4a3beff8841ee4461313c3498d1ef630 Mon Sep 17 00:00:00 2001 From: Adam Harwayne Date: Tue, 12 Mar 2019 10:18:10 -0700 Subject: [PATCH 138/221] Clean up some spots the merge didn't catch. --- cmd/controller/main.go | 16 ++-- pkg/reconciler/v1alpha1/broker/broker.go | 36 +++----- .../v1alpha1/namespace/namespace.go | 50 +++++------ pkg/reconciler/v1alpha1/trigger/trigger.go | 90 +++++++++---------- 4 files changed, 87 insertions(+), 105 deletions(-) diff --git a/cmd/controller/main.go b/cmd/controller/main.go index 6030e5456f9..51339cc291a 100644 --- a/cmd/controller/main.go +++ b/cmd/controller/main.go @@ -125,26 +125,26 @@ func main() { providers := []ProvideFunc{ subscription.ProvideController, channel.ProvideController, - broker.ProvideController(logger.Desugar(), + broker.ProvideController( broker.ReconcilerArgs{ IngressImage: getRequiredEnv("BROKER_INGRESS_IMAGE"), IngressServiceAccountName: getRequiredEnv("BROKER_INGRESS_SERVICE_ACCOUNT"), FilterImage: getRequiredEnv("BROKER_FILTER_IMAGE"), FilterServiceAccountName: getRequiredEnv("BROKER_FILTER_SERVICE_ACCOUNT"), }), - trigger.ProvideController(logger.Desugar()), - namespace.ProvideController(logger.Desugar()), + trigger.ProvideController, + namespace.ProvideController, } for _, provider := range providers { - if _, err := provider(mgr, logger.Desugar()); err != nil { + if _, err = provider(mgr, logger.Desugar()); err != nil { logger.Fatalf("Error adding controller to manager: %v", err) } } // Start the Manager go func() { - if err := mgr.Start(stopCh); err != nil { - logger.Fatalf("Error starting manager: %v", err) + if localErr := mgr.Start(stopCh); localErr != nil { + logger.Fatalf("Error starting manager: %v", localErr) } }() @@ -153,8 +153,8 @@ func main() { http.Handle(metricsScrapePath, promhttp.Handler()) go func() { logger.Infof("Starting metrics listener at %s", metricsScrapeAddr) - if err := srv.ListenAndServe(); err != nil { - logger.Infof("Httpserver: ListenAndServe() finished with error: %s", err) + if localErr := srv.ListenAndServe(); localErr != nil { + logger.Infof("Httpserver: ListenAndServe() finished with error: %s", localErr) } }() diff --git a/pkg/reconciler/v1alpha1/broker/broker.go b/pkg/reconciler/v1alpha1/broker/broker.go index 3ad3854589b..afce06aebab 100644 --- a/pkg/reconciler/v1alpha1/broker/broker.go +++ b/pkg/reconciler/v1alpha1/broker/broker.go @@ -21,38 +21,30 @@ import ( "fmt" "time" - "k8s.io/apimachinery/pkg/runtime" - - "k8s.io/client-go/rest" - "k8s.io/client-go/tools/record" - "sigs.k8s.io/controller-runtime/pkg/controller" - "sigs.k8s.io/controller-runtime/pkg/handler" - "sigs.k8s.io/controller-runtime/pkg/manager" - "sigs.k8s.io/controller-runtime/pkg/source" - + "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" + "github.com/knative/eventing/pkg/logging" "github.com/knative/eventing/pkg/reconciler/names" - - "github.com/knative/eventing/contrib/gcppubsub/pkg/util/logging" - v1 "k8s.io/api/apps/v1" - - "k8s.io/apimachinery/pkg/labels" - "k8s.io/apimachinery/pkg/runtime/schema" - "github.com/knative/eventing/pkg/reconciler/v1alpha1/broker/resources" - "go.uber.org/zap" - - "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" + v1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/equality" "k8s.io/apimachinery/pkg/api/errors" k8serrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/record" "sigs.k8s.io/controller-runtime/pkg/client" runtimeclient "sigs.k8s.io/controller-runtime/pkg/client" - + "sigs.k8s.io/controller-runtime/pkg/controller" + "sigs.k8s.io/controller-runtime/pkg/handler" + "sigs.k8s.io/controller-runtime/pkg/manager" "sigs.k8s.io/controller-runtime/pkg/reconcile" + "sigs.k8s.io/controller-runtime/pkg/source" ) const ( @@ -89,8 +81,8 @@ type ReconcilerArgs struct { } // ProvideController returns a function that returns a Broker controller. -func ProvideController(logger *zap.Logger, args ReconcilerArgs) func(manager.Manager) (controller.Controller, error) { - return func(mgr manager.Manager) (controller.Controller, error) { +func ProvideController(args ReconcilerArgs) func(manager.Manager, *zap.Logger) (controller.Controller, error) { + return func(mgr manager.Manager, logger *zap.Logger) (controller.Controller, error) { // Setup a new controller to Reconcile Brokers. c, err := controller.New(controllerAgentName, mgr, controller.Options{ Reconciler: &reconciler{ diff --git a/pkg/reconciler/v1alpha1/namespace/namespace.go b/pkg/reconciler/v1alpha1/namespace/namespace.go index a8fd331b4bf..e5272122b13 100644 --- a/pkg/reconciler/v1alpha1/namespace/namespace.go +++ b/pkg/reconciler/v1alpha1/namespace/namespace.go @@ -20,8 +20,8 @@ import ( "context" "fmt" - "github.com/knative/eventing/contrib/gcppubsub/pkg/util/logging" "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" + "github.com/knative/eventing/pkg/logging" "go.uber.org/zap" corev1 "k8s.io/api/core/v1" v1 "k8s.io/api/core/v1" @@ -73,35 +73,33 @@ type reconciler struct { var _ reconcile.Reconciler = &reconciler{} // ProvideController returns a function that returns a Namespace controller. -func ProvideController(logger *zap.Logger) func(manager.Manager) (controller.Controller, error) { - return func(mgr manager.Manager) (controller.Controller, error) { - // Setup a new controller to Reconcile Namespaces. - r := &reconciler{ - recorder: mgr.GetRecorder(controllerAgentName), - logger: logger, - } - c, err := controller.New(controllerAgentName, mgr, controller.Options{ - Reconciler: r, - }) - if err != nil { - return nil, err - } +func ProvideController(mgr manager.Manager, logger *zap.Logger) (controller.Controller, error) { + // Setup a new controller to Reconcile Namespaces. + r := &reconciler{ + recorder: mgr.GetRecorder(controllerAgentName), + logger: logger, + } + c, err := controller.New(controllerAgentName, mgr, controller.Options{ + Reconciler: r, + }) + if err != nil { + return nil, err + } - // Watch Namespaces. - if err = c.Watch(&source.Kind{Type: &v1.Namespace{}}, &handler.EnqueueRequestForObject{}); err != nil { - return nil, err - } + // Watch Namespaces. + if err = c.Watch(&source.Kind{Type: &v1.Namespace{}}, &handler.EnqueueRequestForObject{}); err != nil { + return nil, err + } - // Watch all the resources that this reconciler reconciles. - for _, t := range []runtime.Object{&corev1.ServiceAccount{}, &rbacv1.RoleBinding{}, &v1alpha1.Broker{}} { - err = c.Watch(&source.Kind{Type: t}, &handler.EnqueueRequestsFromMapFunc{ToRequests: &namespaceMapper{}}) - if err != nil { - return nil, err - } + // Watch all the resources that this reconciler reconciles. + for _, t := range []runtime.Object{&corev1.ServiceAccount{}, &rbacv1.RoleBinding{}, &v1alpha1.Broker{}} { + err = c.Watch(&source.Kind{Type: t}, &handler.EnqueueRequestsFromMapFunc{ToRequests: &namespaceMapper{}}) + if err != nil { + return nil, err } - - return c, nil } + + return c, nil } type namespaceMapper struct{} diff --git a/pkg/reconciler/v1alpha1/trigger/trigger.go b/pkg/reconciler/v1alpha1/trigger/trigger.go index 70529f16740..ff7bc56531e 100644 --- a/pkg/reconciler/v1alpha1/trigger/trigger.go +++ b/pkg/reconciler/v1alpha1/trigger/trigger.go @@ -21,26 +21,13 @@ import ( "fmt" "sync" - "github.com/knative/eventing/pkg/utils" - + "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" + "github.com/knative/eventing/pkg/logging" "github.com/knative/eventing/pkg/provisioners" - - "k8s.io/apimachinery/pkg/runtime" - - "k8s.io/client-go/dynamic" - "k8s.io/client-go/rest" - "k8s.io/client-go/tools/record" - "sigs.k8s.io/controller-runtime/pkg/controller" - "sigs.k8s.io/controller-runtime/pkg/handler" - "sigs.k8s.io/controller-runtime/pkg/manager" - "sigs.k8s.io/controller-runtime/pkg/source" - "github.com/knative/eventing/pkg/reconciler/names" - - "github.com/knative/eventing/contrib/gcppubsub/pkg/util/logging" - "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" "github.com/knative/eventing/pkg/reconciler/v1alpha1/broker" "github.com/knative/eventing/pkg/reconciler/v1alpha1/subscription" + "github.com/knative/eventing/pkg/utils" istiov1alpha3 "github.com/knative/pkg/apis/istio/v1alpha3" "go.uber.org/zap" corev1 "k8s.io/api/core/v1" @@ -49,12 +36,19 @@ import ( k8serrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/dynamic" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/record" "sigs.k8s.io/controller-runtime/pkg/client" runtimeclient "sigs.k8s.io/controller-runtime/pkg/client" - + "sigs.k8s.io/controller-runtime/pkg/controller" + "sigs.k8s.io/controller-runtime/pkg/handler" + "sigs.k8s.io/controller-runtime/pkg/manager" "sigs.k8s.io/controller-runtime/pkg/reconcile" + "sigs.k8s.io/controller-runtime/pkg/source" ) const ( @@ -93,44 +87,42 @@ type reconciler struct { var _ reconcile.Reconciler = &reconciler{} // ProvideController returns a function that returns a Trigger controller. -func ProvideController(logger *zap.Logger) func(manager.Manager) (controller.Controller, error) { - return func(mgr manager.Manager) (controller.Controller, error) { - // Setup a new controller to Reconcile Triggers. - r := &reconciler{ - recorder: mgr.GetRecorder(controllerAgentName), - logger: logger, - triggers: make(map[types.NamespacedName]map[reconcile.Request]struct{}), - } - c, err := controller.New(controllerAgentName, mgr, controller.Options{ - Reconciler: r, - }) - if err != nil { - return nil, err - } - - // Watch Triggers. - if err = c.Watch(&source.Kind{Type: &v1alpha1.Trigger{}}, &handler.EnqueueRequestForObject{}); err != nil { - return nil, err - } +func ProvideController(mgr manager.Manager, logger *zap.Logger) (controller.Controller, error) { + // Setup a new controller to Reconcile Triggers. + r := &reconciler{ + recorder: mgr.GetRecorder(controllerAgentName), + logger: logger, + triggers: make(map[types.NamespacedName]map[reconcile.Request]struct{}), + } + c, err := controller.New(controllerAgentName, mgr, controller.Options{ + Reconciler: r, + }) + if err != nil { + return nil, err + } - // Watch all the resources that the Trigger reconciles. - for _, t := range []runtime.Object{&corev1.Service{}, &istiov1alpha3.VirtualService{}, &v1alpha1.Subscription{}} { - err = c.Watch(&source.Kind{Type: t}, &handler.EnqueueRequestForOwner{OwnerType: &v1alpha1.Trigger{}, IsController: true}) - if err != nil { - return nil, err - } - } + // Watch Triggers. + if err = c.Watch(&source.Kind{Type: &v1alpha1.Trigger{}}, &handler.EnqueueRequestForObject{}); err != nil { + return nil, err + } - // Watch for Broker changes. - if err = c.Watch(&source.Kind{Type: &v1alpha1.Broker{}}, &handler.EnqueueRequestsFromMapFunc{ToRequests: &mapAllTriggers{r}}); err != nil { + // Watch all the resources that the Trigger reconciles. + for _, t := range []runtime.Object{&corev1.Service{}, &istiov1alpha3.VirtualService{}, &v1alpha1.Subscription{}} { + err = c.Watch(&source.Kind{Type: t}, &handler.EnqueueRequestForOwner{OwnerType: &v1alpha1.Trigger{}, IsController: true}) + if err != nil { return nil, err } + } - // TODO reconcile after a change to the subscriber. I'm not sure how this is possible, but we should do it if we - // can find a way. - - return c, nil + // Watch for Broker changes. + if err = c.Watch(&source.Kind{Type: &v1alpha1.Broker{}}, &handler.EnqueueRequestsFromMapFunc{ToRequests: &mapAllTriggers{r}}); err != nil { + return nil, err } + + // TODO reconcile after a change to the subscriber. I'm not sure how this is possible, but we should do it if we + // can find a way. + + return c, nil } // mapAllTriggers maps Broker change notifications to Trigger reconcileRequests. From 88b4fce626e420ca072f006f8a9b2ea203d87fbd Mon Sep 17 00:00:00 2001 From: nachocano Date: Tue, 12 Mar 2019 14:26:38 -0700 Subject: [PATCH 139/221] updating example --- docs/registry/example_eventtype.yaml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/docs/registry/example_eventtype.yaml b/docs/registry/example_eventtype.yaml index 1e736dea0ee..10e45eed9c5 100644 --- a/docs/registry/example_eventtype.yaml +++ b/docs/registry/example_eventtype.yaml @@ -2,10 +2,12 @@ apiVersion: eventing.knative.dev/v1alpha1 kind: EventType metadata: # advisory - name: com.github.pullrequest + name: dev.knative.source.bitbucket.repo-push spec: # authoritative - type: dev.knative.source.github.pull_request - # cloud event source or knative source? - source: github.com - schema: http://foo2.example/schema + type: dev.knative.source.bitbucket.repo:push + # cloud event source + source: https://bitbucket.org/owner/repo/ + # origin is needed? + origin: bitbucket.org + schema: https://api.bitbucket.org/2.0/schemas/repo/push From 39d1bf6b4636680a0830697add8f531bca4290bc Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Tue, 12 Mar 2019 18:10:29 -0700 Subject: [PATCH 140/221] Removing source --- pkg/apis/eventing/v1alpha1/eventtype_types.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pkg/apis/eventing/v1alpha1/eventtype_types.go b/pkg/apis/eventing/v1alpha1/eventtype_types.go index 174b0a78458..3bc01200598 100644 --- a/pkg/apis/eventing/v1alpha1/eventtype_types.go +++ b/pkg/apis/eventing/v1alpha1/eventtype_types.go @@ -59,9 +59,8 @@ type EventTypeSpec struct { DeprecatedGeneration int64 `json:"generation,omitempty"` // TODO these attributes should be updated once we clarify the UX. - // Type and Source refer to the cloud event type and source. - Type string `json:"type,omitempty"` - Source string `json:"source,omitempty"` + // Type refers to the cloud event type. + Type string `json:"type,omitempty"` // +optional Origin string `json:"origin,omitempty"` // +optional From a4f122db699291d5933bbd46eb9e67a78b03a552 Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Tue, 12 Mar 2019 18:21:58 -0700 Subject: [PATCH 141/221] cluster-scoped registry to simplify things. --- pkg/apis/eventing/v1alpha1/eventtype_types.go | 1 + .../eventing/v1alpha1/eventing_client.go | 4 +- .../typed/eventing/v1alpha1/eventtype.go | 15 +------ .../v1alpha1/fake/fake_eventing_client.go | 4 +- .../eventing/v1alpha1/fake/fake_eventtype.go | 27 +++++-------- .../eventing/v1alpha1/eventtype.go | 13 +++---- .../eventing/v1alpha1/interface.go | 2 +- .../listers/eventing/v1alpha1/eventtype.go | 39 +++---------------- .../eventing/v1alpha1/expansion_generated.go | 4 -- 9 files changed, 28 insertions(+), 81 deletions(-) diff --git a/pkg/apis/eventing/v1alpha1/eventtype_types.go b/pkg/apis/eventing/v1alpha1/eventtype_types.go index 3bc01200598..4a0f000e551 100644 --- a/pkg/apis/eventing/v1alpha1/eventtype_types.go +++ b/pkg/apis/eventing/v1alpha1/eventtype_types.go @@ -25,6 +25,7 @@ import ( ) // +genclient +// +genclient:nonNamespaced // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object type EventType struct { diff --git a/pkg/client/clientset/versioned/typed/eventing/v1alpha1/eventing_client.go b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/eventing_client.go index 033b408a70d..f839f8d366e 100644 --- a/pkg/client/clientset/versioned/typed/eventing/v1alpha1/eventing_client.go +++ b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/eventing_client.go @@ -52,8 +52,8 @@ func (c *EventingV1alpha1Client) ClusterChannelProvisioners() ClusterChannelProv return newClusterChannelProvisioners(c) } -func (c *EventingV1alpha1Client) EventTypes(namespace string) EventTypeInterface { - return newEventTypes(c, namespace) +func (c *EventingV1alpha1Client) EventTypes() EventTypeInterface { + return newEventTypes(c) } func (c *EventingV1alpha1Client) Subscriptions(namespace string) SubscriptionInterface { diff --git a/pkg/client/clientset/versioned/typed/eventing/v1alpha1/eventtype.go b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/eventtype.go index 55c445c67ce..1615baf8ea4 100644 --- a/pkg/client/clientset/versioned/typed/eventing/v1alpha1/eventtype.go +++ b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/eventtype.go @@ -30,7 +30,7 @@ import ( // EventTypesGetter has a method to return a EventTypeInterface. // A group's client should implement this interface. type EventTypesGetter interface { - EventTypes(namespace string) EventTypeInterface + EventTypes() EventTypeInterface } // EventTypeInterface has methods to work with EventType resources. @@ -50,14 +50,12 @@ type EventTypeInterface interface { // eventTypes implements EventTypeInterface type eventTypes struct { client rest.Interface - ns string } // newEventTypes returns a EventTypes -func newEventTypes(c *EventingV1alpha1Client, namespace string) *eventTypes { +func newEventTypes(c *EventingV1alpha1Client) *eventTypes { return &eventTypes{ client: c.RESTClient(), - ns: namespace, } } @@ -65,7 +63,6 @@ func newEventTypes(c *EventingV1alpha1Client, namespace string) *eventTypes { func (c *eventTypes) Get(name string, options v1.GetOptions) (result *v1alpha1.EventType, err error) { result = &v1alpha1.EventType{} err = c.client.Get(). - Namespace(c.ns). Resource("eventtypes"). Name(name). VersionedParams(&options, scheme.ParameterCodec). @@ -78,7 +75,6 @@ func (c *eventTypes) Get(name string, options v1.GetOptions) (result *v1alpha1.E func (c *eventTypes) List(opts v1.ListOptions) (result *v1alpha1.EventTypeList, err error) { result = &v1alpha1.EventTypeList{} err = c.client.Get(). - Namespace(c.ns). Resource("eventtypes"). VersionedParams(&opts, scheme.ParameterCodec). Do(). @@ -90,7 +86,6 @@ func (c *eventTypes) List(opts v1.ListOptions) (result *v1alpha1.EventTypeList, func (c *eventTypes) Watch(opts v1.ListOptions) (watch.Interface, error) { opts.Watch = true return c.client.Get(). - Namespace(c.ns). Resource("eventtypes"). VersionedParams(&opts, scheme.ParameterCodec). Watch() @@ -100,7 +95,6 @@ func (c *eventTypes) Watch(opts v1.ListOptions) (watch.Interface, error) { func (c *eventTypes) Create(eventType *v1alpha1.EventType) (result *v1alpha1.EventType, err error) { result = &v1alpha1.EventType{} err = c.client.Post(). - Namespace(c.ns). Resource("eventtypes"). Body(eventType). Do(). @@ -112,7 +106,6 @@ func (c *eventTypes) Create(eventType *v1alpha1.EventType) (result *v1alpha1.Eve func (c *eventTypes) Update(eventType *v1alpha1.EventType) (result *v1alpha1.EventType, err error) { result = &v1alpha1.EventType{} err = c.client.Put(). - Namespace(c.ns). Resource("eventtypes"). Name(eventType.Name). Body(eventType). @@ -127,7 +120,6 @@ func (c *eventTypes) Update(eventType *v1alpha1.EventType) (result *v1alpha1.Eve func (c *eventTypes) UpdateStatus(eventType *v1alpha1.EventType) (result *v1alpha1.EventType, err error) { result = &v1alpha1.EventType{} err = c.client.Put(). - Namespace(c.ns). Resource("eventtypes"). Name(eventType.Name). SubResource("status"). @@ -140,7 +132,6 @@ func (c *eventTypes) UpdateStatus(eventType *v1alpha1.EventType) (result *v1alph // Delete takes name of the eventType and deletes it. Returns an error if one occurs. func (c *eventTypes) Delete(name string, options *v1.DeleteOptions) error { return c.client.Delete(). - Namespace(c.ns). Resource("eventtypes"). Name(name). Body(options). @@ -151,7 +142,6 @@ func (c *eventTypes) Delete(name string, options *v1.DeleteOptions) error { // DeleteCollection deletes a collection of objects. func (c *eventTypes) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { return c.client.Delete(). - Namespace(c.ns). Resource("eventtypes"). VersionedParams(&listOptions, scheme.ParameterCodec). Body(options). @@ -163,7 +153,6 @@ func (c *eventTypes) DeleteCollection(options *v1.DeleteOptions, listOptions v1. func (c *eventTypes) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.EventType, err error) { result = &v1alpha1.EventType{} err = c.client.Patch(pt). - Namespace(c.ns). Resource("eventtypes"). SubResource(subresources...). Name(name). diff --git a/pkg/client/clientset/versioned/typed/eventing/v1alpha1/fake/fake_eventing_client.go b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/fake/fake_eventing_client.go index c14e2b271de..efb17feed5e 100644 --- a/pkg/client/clientset/versioned/typed/eventing/v1alpha1/fake/fake_eventing_client.go +++ b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/fake/fake_eventing_client.go @@ -40,8 +40,8 @@ func (c *FakeEventingV1alpha1) ClusterChannelProvisioners() v1alpha1.ClusterChan return &FakeClusterChannelProvisioners{c} } -func (c *FakeEventingV1alpha1) EventTypes(namespace string) v1alpha1.EventTypeInterface { - return &FakeEventTypes{c, namespace} +func (c *FakeEventingV1alpha1) EventTypes() v1alpha1.EventTypeInterface { + return &FakeEventTypes{c} } func (c *FakeEventingV1alpha1) Subscriptions(namespace string) v1alpha1.SubscriptionInterface { diff --git a/pkg/client/clientset/versioned/typed/eventing/v1alpha1/fake/fake_eventtype.go b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/fake/fake_eventtype.go index 592074ffad5..2b914974d91 100644 --- a/pkg/client/clientset/versioned/typed/eventing/v1alpha1/fake/fake_eventtype.go +++ b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/fake/fake_eventtype.go @@ -31,7 +31,6 @@ import ( // FakeEventTypes implements EventTypeInterface type FakeEventTypes struct { Fake *FakeEventingV1alpha1 - ns string } var eventtypesResource = schema.GroupVersionResource{Group: "eventing.knative.dev", Version: "v1alpha1", Resource: "eventtypes"} @@ -41,8 +40,7 @@ var eventtypesKind = schema.GroupVersionKind{Group: "eventing.knative.dev", Vers // 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 *v1alpha1.EventType, err error) { obj, err := c.Fake. - Invokes(testing.NewGetAction(eventtypesResource, c.ns, name), &v1alpha1.EventType{}) - + Invokes(testing.NewRootGetAction(eventtypesResource, name), &v1alpha1.EventType{}) if obj == nil { return nil, err } @@ -52,8 +50,7 @@ func (c *FakeEventTypes) Get(name string, options v1.GetOptions) (result *v1alph // List takes label and field selectors, and returns the list of EventTypes that match those selectors. func (c *FakeEventTypes) List(opts v1.ListOptions) (result *v1alpha1.EventTypeList, err error) { obj, err := c.Fake. - Invokes(testing.NewListAction(eventtypesResource, eventtypesKind, c.ns, opts), &v1alpha1.EventTypeList{}) - + Invokes(testing.NewRootListAction(eventtypesResource, eventtypesKind, opts), &v1alpha1.EventTypeList{}) if obj == nil { return nil, err } @@ -74,15 +71,13 @@ func (c *FakeEventTypes) List(opts v1.ListOptions) (result *v1alpha1.EventTypeLi // 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)) - + InvokesWatch(testing.NewRootWatchAction(eventtypesResource, 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 *v1alpha1.EventType) (result *v1alpha1.EventType, err error) { obj, err := c.Fake. - Invokes(testing.NewCreateAction(eventtypesResource, c.ns, eventType), &v1alpha1.EventType{}) - + Invokes(testing.NewRootCreateAction(eventtypesResource, eventType), &v1alpha1.EventType{}) if obj == nil { return nil, err } @@ -92,8 +87,7 @@ func (c *FakeEventTypes) Create(eventType *v1alpha1.EventType) (result *v1alpha1 // 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 *v1alpha1.EventType) (result *v1alpha1.EventType, err error) { obj, err := c.Fake. - Invokes(testing.NewUpdateAction(eventtypesResource, c.ns, eventType), &v1alpha1.EventType{}) - + Invokes(testing.NewRootUpdateAction(eventtypesResource, eventType), &v1alpha1.EventType{}) if obj == nil { return nil, err } @@ -104,8 +98,7 @@ func (c *FakeEventTypes) Update(eventType *v1alpha1.EventType) (result *v1alpha1 // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). func (c *FakeEventTypes) UpdateStatus(eventType *v1alpha1.EventType) (*v1alpha1.EventType, error) { obj, err := c.Fake. - Invokes(testing.NewUpdateSubresourceAction(eventtypesResource, "status", c.ns, eventType), &v1alpha1.EventType{}) - + Invokes(testing.NewRootUpdateSubresourceAction(eventtypesResource, "status", eventType), &v1alpha1.EventType{}) if obj == nil { return nil, err } @@ -115,14 +108,13 @@ func (c *FakeEventTypes) UpdateStatus(eventType *v1alpha1.EventType) (*v1alpha1. // 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), &v1alpha1.EventType{}) - + Invokes(testing.NewRootDeleteAction(eventtypesResource, name), &v1alpha1.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) + action := testing.NewRootDeleteCollectionAction(eventtypesResource, listOptions) _, err := c.Fake.Invokes(action, &v1alpha1.EventTypeList{}) return err @@ -131,8 +123,7 @@ func (c *FakeEventTypes) DeleteCollection(options *v1.DeleteOptions, listOptions // Patch applies the patch and returns the patched eventType. func (c *FakeEventTypes) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.EventType, err error) { obj, err := c.Fake. - Invokes(testing.NewPatchSubresourceAction(eventtypesResource, c.ns, name, data, subresources...), &v1alpha1.EventType{}) - + Invokes(testing.NewRootPatchSubresourceAction(eventtypesResource, name, data, subresources...), &v1alpha1.EventType{}) if obj == nil { return nil, err } diff --git a/pkg/client/informers/externalversions/eventing/v1alpha1/eventtype.go b/pkg/client/informers/externalversions/eventing/v1alpha1/eventtype.go index 9e62ba5e723..3f1617c7c94 100644 --- a/pkg/client/informers/externalversions/eventing/v1alpha1/eventtype.go +++ b/pkg/client/informers/externalversions/eventing/v1alpha1/eventtype.go @@ -41,33 +41,32 @@ type EventTypeInformer interface { 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) +func NewEventTypeInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredEventTypeInformer(client, 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 { +func NewFilteredEventTypeInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { return cache.NewSharedIndexInformer( &cache.ListWatch{ ListFunc: func(options v1.ListOptions) (runtime.Object, error) { if tweakListOptions != nil { tweakListOptions(&options) } - return client.EventingV1alpha1().EventTypes(namespace).List(options) + return client.EventingV1alpha1().EventTypes().List(options) }, WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { if tweakListOptions != nil { tweakListOptions(&options) } - return client.EventingV1alpha1().EventTypes(namespace).Watch(options) + return client.EventingV1alpha1().EventTypes().Watch(options) }, }, &eventing_v1alpha1.EventType{}, @@ -77,7 +76,7 @@ func NewFilteredEventTypeInformer(client versioned.Interface, namespace string, } 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) + return NewFilteredEventTypeInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) } func (f *eventTypeInformer) Informer() cache.SharedIndexInformer { diff --git a/pkg/client/informers/externalversions/eventing/v1alpha1/interface.go b/pkg/client/informers/externalversions/eventing/v1alpha1/interface.go index d272412d038..81012e920e8 100644 --- a/pkg/client/informers/externalversions/eventing/v1alpha1/interface.go +++ b/pkg/client/informers/externalversions/eventing/v1alpha1/interface.go @@ -66,7 +66,7 @@ func (v *version) ClusterChannelProvisioners() ClusterChannelProvisionerInformer // EventTypes returns a EventTypeInformer. func (v *version) EventTypes() EventTypeInformer { - return &eventTypeInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} + return &eventTypeInformer{factory: v.factory, tweakListOptions: v.tweakListOptions} } // Subscriptions returns a SubscriptionInformer. diff --git a/pkg/client/listers/eventing/v1alpha1/eventtype.go b/pkg/client/listers/eventing/v1alpha1/eventtype.go index ffbdf6afdd5..e3fb4b3c0d2 100644 --- a/pkg/client/listers/eventing/v1alpha1/eventtype.go +++ b/pkg/client/listers/eventing/v1alpha1/eventtype.go @@ -29,8 +29,8 @@ import ( type EventTypeLister interface { // List lists all EventTypes in the indexer. List(selector labels.Selector) (ret []*v1alpha1.EventType, err error) - // EventTypes returns an object that can list and get EventTypes. - EventTypes(namespace string) EventTypeNamespaceLister + // Get retrieves the EventType from the index for a given name. + Get(name string) (*v1alpha1.EventType, error) EventTypeListerExpansion } @@ -52,38 +52,9 @@ func (s *eventTypeLister) List(selector labels.Selector) (ret []*v1alpha1.EventT 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 []*v1alpha1.EventType, err error) - // Get retrieves the EventType from the indexer for a given namespace and name. - Get(name string) (*v1alpha1.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 []*v1alpha1.EventType, err error) { - err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { - ret = append(ret, m.(*v1alpha1.EventType)) - }) - return ret, err -} - -// Get retrieves the EventType from the indexer for a given namespace and name. -func (s eventTypeNamespaceLister) Get(name string) (*v1alpha1.EventType, error) { - obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) +// Get retrieves the EventType from the index for a given name. +func (s *eventTypeLister) Get(name string) (*v1alpha1.EventType, error) { + obj, exists, err := s.indexer.GetByKey(name) if err != nil { return nil, err } diff --git a/pkg/client/listers/eventing/v1alpha1/expansion_generated.go b/pkg/client/listers/eventing/v1alpha1/expansion_generated.go index 66326fa3477..291586b3881 100644 --- a/pkg/client/listers/eventing/v1alpha1/expansion_generated.go +++ b/pkg/client/listers/eventing/v1alpha1/expansion_generated.go @@ -42,10 +42,6 @@ type ClusterChannelProvisionerListerExpansion interface{} // EventTypeLister. type EventTypeListerExpansion interface{} -// EventTypeNamespaceListerExpansion allows custom methods to be added to -// EventTypeNamespaceLister. -type EventTypeNamespaceListerExpansion interface{} - // SubscriptionListerExpansion allows custom methods to be added to // SubscriptionLister. type SubscriptionListerExpansion interface{} From 84f080c7d66057e100cb10d99c62660285d7ff3c Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Tue, 12 Mar 2019 18:23:00 -0700 Subject: [PATCH 142/221] updating example --- docs/registry/example_eventtype.yaml | 3 --- 1 file changed, 3 deletions(-) diff --git a/docs/registry/example_eventtype.yaml b/docs/registry/example_eventtype.yaml index 10e45eed9c5..82f6f5805ff 100644 --- a/docs/registry/example_eventtype.yaml +++ b/docs/registry/example_eventtype.yaml @@ -6,8 +6,5 @@ metadata: spec: # authoritative type: dev.knative.source.bitbucket.repo:push - # cloud event source - source: https://bitbucket.org/owner/repo/ - # origin is needed? origin: bitbucket.org schema: https://api.bitbucket.org/2.0/schemas/repo/push From 19c0d4560beb8750154bba28e0b4b3a5513c3b68 Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Tue, 12 Mar 2019 18:24:04 -0700 Subject: [PATCH 143/221] removing source --- config/300-eventtype.yaml | 3 --- 1 file changed, 3 deletions(-) diff --git a/config/300-eventtype.yaml b/config/300-eventtype.yaml index 5f6c4bc2b64..a36b138bf48 100644 --- a/config/300-eventtype.yaml +++ b/config/300-eventtype.yaml @@ -33,9 +33,6 @@ spec: - name: Type type: string JSONPath: ".spec.type" - - name: Source - type: string - JSONPath: ".spec.source" - name: Origin type: string JSONPath: ".spec.origin" From 99f847352544953a88c6e2875480106f3aa31389 Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Wed, 13 Mar 2019 00:48:33 -0700 Subject: [PATCH 144/221] updating broker policy to create event types... updating cloud event SDK version. --- Gopkg.lock | 5 +- Gopkg.toml | 4 +- cmd/broker/ingress/main.go | 26 ++-- pkg/broker/ingress.go | 111 +++++++++++++++--- .../pkg/cloudevents/datacodec/xml/data.go | 4 +- .../sdk-go/pkg/cloudevents/event_response.go | 29 +++++ .../sdk-go/pkg/cloudevents/types/timestamp.go | 29 ++++- .../sdk-go/pkg/cloudevents/types/urlref.go | 23 +++- 8 files changed, 193 insertions(+), 38 deletions(-) create mode 100644 vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/event_response.go diff --git a/Gopkg.lock b/Gopkg.lock index 0edd1755782..8dfb4cf49b8 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -58,7 +58,7 @@ version = "v2.1.15" [[projects]] - digest = "1:a12b641b81e00b8444bed01357098490ab769dbce31de3410b64c46a23a06287" + digest = "1:2beba0dcb017749e7fa3c5bd9397f63e33ace2213787bb5383bdc49a9d678a8a" name = "github.com/cloudevents/sdk-go" packages = [ "pkg/cloudevents", @@ -68,7 +68,8 @@ "pkg/cloudevents/types", ] pruneopts = "NUT" - revision = "d50361a5655081514f406b4e672d72e9886c17ad" + revision = "c1a6fb0cc8226884014fb5063ab406ed9504a663" + version = "0.4.0" [[projects]] digest = "1:ffe9824d294da03b391f44e1ae8281281b4afc1bdaa9588c9097785e3af10cec" diff --git a/Gopkg.toml b/Gopkg.toml index 21f0b87e726..dd87ac5b8e4 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -130,8 +130,6 @@ required = [ name = "github.com/nats-io/nats-streaming-server" version = "0.11.0" -# Use CloudEvents, master as of Feb 28, 2019 -# Will use releases as soon as they get releases going. [[override]] name = "github.com/cloudevents/sdk-go" - revision = "d50361a5655081514f406b4e672d72e9886c17ad" + version = "0.4.0" diff --git a/cmd/broker/ingress/main.go b/cmd/broker/ingress/main.go index 33fdecf75bf..c35bad2fa3e 100644 --- a/cmd/broker/ingress/main.go +++ b/cmd/broker/ingress/main.go @@ -52,6 +52,8 @@ const ( v2EventId = "Ce-Id" v2EventType = "Ce-Type" v2EventSource = "Ce-Source" + // Extension attribute. + eventOrigin = "Ce-Origin" ) var ( @@ -140,7 +142,7 @@ func NewHandler(logger *zap.Logger, destination, policy string, client client.Cl handler := &Handler{ logger: logger, dispatcher: provisioners.NewMessageDispatcher(logger.Sugar()), - ingressPolicy: broker.NewIngressPolicy(client, policy), + ingressPolicy: broker.NewIngressPolicy(logger.Sugar(), client, policy), destination: fmt.Sprintf("http://%s", destination), client: client, } @@ -155,7 +157,7 @@ func NewHandler(logger *zap.Logger, destination, policy string, client client.Cl func createReceiverFunction(f *Handler) func(provisioners.ChannelReference, *provisioners.Message) error { return func(c provisioners.ChannelReference, m *provisioners.Message) error { event := cloudEventFrom(m) - if f.ingressPolicy.AllowEvent(c.Namespace, &event) { + if f.ingressPolicy.AllowEvent(&event) { return f.dispatch(m) } return nil @@ -192,19 +194,25 @@ func (r *runnableServer) Start(<-chan struct{}) error { // TODO this should be removed once we update the interfaces and start using cloudevents.Event instead of Message. func cloudEventFrom(m *provisioners.Message) cloudevents.Event { event := cloudevents.Event{} + // TODO better way to set extensions. + var extensions map[string]interface{} + if origin, ok := m.Headers[eventOrigin]; ok { + extensions[eventOrigin] = origin + } if eventType, ok := m.Headers[v2EventType]; ok { event.Context = cloudevents.EventContextV02{ - ID: m.Headers[v2EventId], - Type: eventType, - Source: *types.ParseURLRef(v2EventSource), + ID: m.Headers[v2EventId], + Type: eventType, + Source: *types.ParseURLRef(v2EventSource), + Extensions: extensions, }.AsV02() } else { event.Context = cloudevents.EventContextV01{ - EventID: m.Headers[v1EventId], - EventType: m.Headers[v1EventType], - Source: *types.ParseURLRef(v1EventSource), + EventID: m.Headers[v1EventId], + EventType: m.Headers[v1EventType], + Source: *types.ParseURLRef(v1EventSource), + Extensions: extensions, }.AsV01() } - event.Data = m.Payload return event } diff --git a/pkg/broker/ingress.go b/pkg/broker/ingress.go index f42e14231bb..6e7ae68bb14 100644 --- a/pkg/broker/ingress.go +++ b/pkg/broker/ingress.go @@ -18,10 +18,18 @@ package broker import ( "context" + "fmt" + "regexp" + "strings" + + "go.uber.org/zap" + + "k8s.io/apimachinery/pkg/util/validation" "github.com/cloudevents/sdk-go/pkg/cloudevents" eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" + k8serrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/client" ) @@ -29,42 +37,85 @@ import ( const ( allowAny = "allow_any" allowRegisteredTypes = "allow_registered" + autoCreate = "auto_create" +) + +var ( + // Only allow alphanumeric, '-' or '.'. + validChars = regexp.MustCompile(`[^-\.a-z0-9]+`) + // EventType not found error. + notFound = k8serrors.NewNotFound(eventingv1alpha1.Resource("eventtype"), "") ) type IngressPolicy interface { - AllowEvent(namespace string, event *cloudevents.Event) bool + AllowEvent(event *cloudevents.Event) bool } -type AllowAnyPolicy struct{} +type Any struct{} + +type Registered struct { + logger *zap.SugaredLogger + client client.Client +} -type AllowRegisteredPolicy struct { +type AutoCreate struct { + logger *zap.SugaredLogger client client.Client } -func NewIngressPolicy(client client.Client, policy string) IngressPolicy { - return newIngressPolicy(client, policy) +func NewIngressPolicy(logger *zap.SugaredLogger, client client.Client, policy string) IngressPolicy { + return newIngressPolicy(logger, client, policy) } -func newIngressPolicy(client client.Client, policy string) IngressPolicy { +func newIngressPolicy(logger *zap.SugaredLogger, client client.Client, policy string) IngressPolicy { switch policy { case allowRegisteredTypes: - return &AllowRegisteredPolicy{ + return &Registered{ + logger: logger, + client: client, + } + case autoCreate: + return &AutoCreate{ + logger: logger, client: client, } case allowAny: - return &AllowAnyPolicy{} + return &Any{} default: - return &AllowAnyPolicy{} + return &Any{} + } +} + +func (p *Any) AllowEvent(event *cloudevents.Event) bool { + return true +} + +func (p *Registered) AllowEvent(event *cloudevents.Event) bool { + _, err := getEventType(p.client, event) + if k8serrors.IsNotFound(err) { + p.logger.Warnf("EventType not found, spec.type %q, %v", event.Type(), err) + } else if err != nil { + p.logger.Errorf("Error retrieving EventType, spec.type %q, %v", event.Type(), err) } + return err != nil } -func (p *AllowAnyPolicy) AllowEvent(namespace string, event *cloudevents.Event) bool { +func (p *AutoCreate) AllowEvent(event *cloudevents.Event) bool { + _, err := getEventType(p.client, event) + if k8serrors.IsNotFound(err) { + eventType := makeEventType(event) + err := p.client.Create(context.TODO(), eventType) + if err != nil { + p.logger.Errorf("Error creating EventType, spec.type %q, %v", event.Type(), err) + } + } else if err != nil { + p.logger.Errorf("Error retrieving EventType, spec.type %q, %v", event.Type(), err) + } return true } -func (p *AllowRegisteredPolicy) AllowEvent(namespace string, event *cloudevents.Event) bool { +func getEventType(c client.Client, event *cloudevents.Event) (*eventingv1alpha1.EventType, error) { opts := &client.ListOptions{ - Namespace: namespace, // Set Raw because if we need to get more than one page, then we will put the continue token // into opts.Raw.Continue. Raw: &metav1.ListOptions{}, @@ -76,19 +127,47 @@ func (p *AllowRegisteredPolicy) AllowEvent(namespace string, event *cloudevents. // but it is not supported. for { el := &eventingv1alpha1.EventTypeList{} - err := p.client.List(ctx, opts, el) + err := c.List(ctx, opts, el) if err != nil { - return false + return nil, err } for _, e := range el.Items { + // TODO ask Scott for better queries to get extensions. + // e.Spec.Origin == event.Extensions("Origin") && e.Spec.Schema == event.Extensions("Schema") if e.Spec.Type == event.Type() { - return true + return &e, nil } } if el.Continue != "" { opts.Raw.Continue = el.Continue } else { - return false + return nil, notFound } } } + +// makeEventType generates, but does not create an EventType from the given cloudevents.Event. +func makeEventType(event *cloudevents.Event) *eventingv1alpha1.EventType { + cloudEventType := event.Type() + return &eventingv1alpha1.EventType{ + ObjectMeta: metav1.ObjectMeta{ + GenerateName: fmt.Sprintf("%s-", toValidIdentifier(cloudEventType)), + // TODO maybe some label? + }, + Spec: eventingv1alpha1.EventTypeSpec{ + Type: cloudEventType, + Origin: "", // event.Extensions("Origin") + Schema: "", // event.Extensions("Schema") + }, + } +} + +func toValidIdentifier(cloudEventType string) string { + if msgs := validation.IsDNS1123Subdomain(cloudEventType); len(msgs) != 0 { + // If it is not a valid DNS1123 name, make it a valid one. + // TODO take care of size < 63, and starting and end indexes should be alphanumeric. + cloudEventType = strings.ToLower(cloudEventType) + cloudEventType = validChars.ReplaceAllString(cloudEventType, "-") + } + return cloudEventType +} diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/datacodec/xml/data.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/datacodec/xml/data.go index fb36f2eb285..a904a250c07 100644 --- a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/datacodec/xml/data.go +++ b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/datacodec/xml/data.go @@ -26,7 +26,7 @@ func Decode(in, out interface{}) error { if len(b) > 1 && (b[0] == byte('"') || (b[0] == byte('\\') && b[1] == byte('"'))) { s, err := strconv.Unquote(string(b)) if err != nil { - return err + return fmt.Errorf("[xml] failed to unquote quoted data: %s", err.Error()) } if len(s) > 0 && s[0] == '<' { // looks like xml, use it @@ -35,7 +35,7 @@ func Decode(in, out interface{}) error { // looks like base64, decode bs, err := base64.StdEncoding.DecodeString(s) if err != nil { - return err + return fmt.Errorf("[xml] failed to decode base64 encoded string: %s", err.Error()) } b = bs } diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/event_response.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/event_response.go new file mode 100644 index 00000000000..b8e09746204 --- /dev/null +++ b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/event_response.go @@ -0,0 +1,29 @@ +package cloudevents + +// EventResponse represents the canonical representation of a Response to a +// CloudEvent from a receiver. +type EventResponse struct { + Status int + Event *Event + Reason string +} + +func (e *EventResponse) RespondWith(status int, event *Event) { + if e == nil { + // if nil, response not supported + return + } + e.Status = status + if event != nil { + e.Event = event + } +} + +func (e *EventResponse) Error(status int, reason string) { + if e == nil { + // if nil, response not supported + return + } + e.Status = status + e.Reason = reason +} diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/types/timestamp.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/types/timestamp.go index b535e5dad6d..c87e24804d3 100644 --- a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/types/timestamp.go +++ b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/types/timestamp.go @@ -2,6 +2,7 @@ package types import ( "encoding/json" + "encoding/xml" "fmt" "time" ) @@ -26,7 +27,7 @@ func (t *Timestamp) MarshalJSON() ([]byte, error) { if t == nil || t.IsZero() { return []byte(`""`), nil } - rfc3339 := fmt.Sprintf("%q", t.Format(time.RFC3339Nano)) + rfc3339 := fmt.Sprintf("%q", t.UTC().Format(time.RFC3339Nano)) return []byte(rfc3339), nil } @@ -35,8 +36,26 @@ func (t *Timestamp) UnmarshalJSON(b []byte) error { if err := json.Unmarshal(b, ×tamp); err != nil { return err } - pt := ParseTimestamp(timestamp) - if pt != nil { + if pt := ParseTimestamp(timestamp); pt != nil { + *t = *pt + } + return nil +} + +func (t *Timestamp) MarshalXML(e *xml.Encoder, start xml.StartElement) error { + if t == nil || t.IsZero() { + return e.EncodeElement(nil, start) + } + v := t.UTC().Format(time.RFC3339Nano) + return e.EncodeElement(v, start) +} + +func (t *Timestamp) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { + var timestamp string + if err := d.DecodeElement(×tamp, &start); err != nil { + return err + } + if pt := ParseTimestamp(timestamp); pt != nil { *t = *pt } return nil @@ -44,8 +63,8 @@ func (t *Timestamp) UnmarshalJSON(b []byte) error { func (t *Timestamp) String() string { if t == nil { - return time.Time{}.Format(time.RFC3339Nano) + return time.Time{}.UTC().Format(time.RFC3339Nano) } - return t.Format(time.RFC3339Nano) + return t.UTC().Format(time.RFC3339Nano) } diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/types/urlref.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/types/urlref.go index 0898e4ece8e..f79fafa0860 100644 --- a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/types/urlref.go +++ b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/types/urlref.go @@ -2,6 +2,7 @@ package types import ( "encoding/json" + "encoding/xml" "fmt" "net/url" ) @@ -32,7 +33,27 @@ func (u *URLRef) UnmarshalJSON(b []byte) error { if err := json.Unmarshal(b, &ref); err != nil { return err } - *u = *ParseURLRef(ref) + r := ParseURLRef(ref) + if r != nil { + *u = *r + } + return nil +} + +func (u URLRef) MarshalXML(e *xml.Encoder, start xml.StartElement) error { + v := fmt.Sprintf("%s", u.String()) + return e.EncodeElement(v, start) +} + +func (u *URLRef) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { + var ref string + if err := d.DecodeElement(&ref, &start); err != nil { + return err + } + r := ParseURLRef(ref) + if r != nil { + *u = *r + } return nil } From 0fae1b31412fe93ac3d5db34678293337c3d5e70 Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Wed, 13 Mar 2019 10:14:20 -0700 Subject: [PATCH 145/221] adding a TODO to update to a cluster-level role binding for the ingress. If we are planning on using cluster-scoped EventTypes --- pkg/reconciler/v1alpha1/namespace/namespace.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/reconciler/v1alpha1/namespace/namespace.go b/pkg/reconciler/v1alpha1/namespace/namespace.go index 4259e4ec50c..86e1263258d 100644 --- a/pkg/reconciler/v1alpha1/namespace/namespace.go +++ b/pkg/reconciler/v1alpha1/namespace/namespace.go @@ -212,6 +212,7 @@ func (r *reconciler) reconcileBrokerFilterServiceAccount(ctx context.Context, ns // reconcileBrokerIngressServiceAccount reconciles the Broker's ingress service account for Namespace 'ns'. func (r *reconciler) reconcileBrokerIngressServiceAccount(ctx context.Context, ns *corev1.Namespace) (*corev1.ServiceAccount, error) { + // TODO in order to get cluster-scoped EventTypes, we need a ClusterRoleBinding. return r.reconcileBrokerServiceAccount(ctx, ns, brokerIngressSA, ingressServiceAccountCreated) } From 5ee11fc25ce9c2af2a82aa1ba6a65dbce0028a22 Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Wed, 13 Mar 2019 10:18:27 -0700 Subject: [PATCH 146/221] namespaced EventTypes, i.e., registry per namespace --- Gopkg.lock | 1 + pkg/apis/eventing/v1alpha1/eventtype_types.go | 1 - .../eventing/v1alpha1/eventing_client.go | 4 +- .../typed/eventing/v1alpha1/eventtype.go | 15 ++++++- .../v1alpha1/fake/fake_eventing_client.go | 4 +- .../eventing/v1alpha1/fake/fake_eventtype.go | 27 ++++++++----- .../eventing/v1alpha1/eventtype.go | 13 ++++--- .../eventing/v1alpha1/interface.go | 2 +- .../listers/eventing/v1alpha1/eventtype.go | 39 ++++++++++++++++--- .../eventing/v1alpha1/expansion_generated.go | 4 ++ 10 files changed, 82 insertions(+), 28 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index 8dfb4cf49b8..ab36bda89ff 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -1304,6 +1304,7 @@ "k8s.io/apimachinery/pkg/util/sets", "k8s.io/apimachinery/pkg/util/sets/types", "k8s.io/apimachinery/pkg/util/uuid", + "k8s.io/apimachinery/pkg/util/validation", "k8s.io/apimachinery/pkg/util/wait", "k8s.io/apimachinery/pkg/util/yaml", "k8s.io/apimachinery/pkg/watch", diff --git a/pkg/apis/eventing/v1alpha1/eventtype_types.go b/pkg/apis/eventing/v1alpha1/eventtype_types.go index 4a0f000e551..3bc01200598 100644 --- a/pkg/apis/eventing/v1alpha1/eventtype_types.go +++ b/pkg/apis/eventing/v1alpha1/eventtype_types.go @@ -25,7 +25,6 @@ import ( ) // +genclient -// +genclient:nonNamespaced // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object type EventType struct { diff --git a/pkg/client/clientset/versioned/typed/eventing/v1alpha1/eventing_client.go b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/eventing_client.go index f839f8d366e..033b408a70d 100644 --- a/pkg/client/clientset/versioned/typed/eventing/v1alpha1/eventing_client.go +++ b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/eventing_client.go @@ -52,8 +52,8 @@ func (c *EventingV1alpha1Client) ClusterChannelProvisioners() ClusterChannelProv return newClusterChannelProvisioners(c) } -func (c *EventingV1alpha1Client) EventTypes() EventTypeInterface { - return newEventTypes(c) +func (c *EventingV1alpha1Client) EventTypes(namespace string) EventTypeInterface { + return newEventTypes(c, namespace) } func (c *EventingV1alpha1Client) Subscriptions(namespace string) SubscriptionInterface { diff --git a/pkg/client/clientset/versioned/typed/eventing/v1alpha1/eventtype.go b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/eventtype.go index 1615baf8ea4..55c445c67ce 100644 --- a/pkg/client/clientset/versioned/typed/eventing/v1alpha1/eventtype.go +++ b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/eventtype.go @@ -30,7 +30,7 @@ import ( // EventTypesGetter has a method to return a EventTypeInterface. // A group's client should implement this interface. type EventTypesGetter interface { - EventTypes() EventTypeInterface + EventTypes(namespace string) EventTypeInterface } // EventTypeInterface has methods to work with EventType resources. @@ -50,12 +50,14 @@ type EventTypeInterface interface { // eventTypes implements EventTypeInterface type eventTypes struct { client rest.Interface + ns string } // newEventTypes returns a EventTypes -func newEventTypes(c *EventingV1alpha1Client) *eventTypes { +func newEventTypes(c *EventingV1alpha1Client, namespace string) *eventTypes { return &eventTypes{ client: c.RESTClient(), + ns: namespace, } } @@ -63,6 +65,7 @@ func newEventTypes(c *EventingV1alpha1Client) *eventTypes { func (c *eventTypes) Get(name string, options v1.GetOptions) (result *v1alpha1.EventType, err error) { result = &v1alpha1.EventType{} err = c.client.Get(). + Namespace(c.ns). Resource("eventtypes"). Name(name). VersionedParams(&options, scheme.ParameterCodec). @@ -75,6 +78,7 @@ func (c *eventTypes) Get(name string, options v1.GetOptions) (result *v1alpha1.E func (c *eventTypes) List(opts v1.ListOptions) (result *v1alpha1.EventTypeList, err error) { result = &v1alpha1.EventTypeList{} err = c.client.Get(). + Namespace(c.ns). Resource("eventtypes"). VersionedParams(&opts, scheme.ParameterCodec). Do(). @@ -86,6 +90,7 @@ func (c *eventTypes) List(opts v1.ListOptions) (result *v1alpha1.EventTypeList, func (c *eventTypes) Watch(opts v1.ListOptions) (watch.Interface, error) { opts.Watch = true return c.client.Get(). + Namespace(c.ns). Resource("eventtypes"). VersionedParams(&opts, scheme.ParameterCodec). Watch() @@ -95,6 +100,7 @@ func (c *eventTypes) Watch(opts v1.ListOptions) (watch.Interface, error) { func (c *eventTypes) Create(eventType *v1alpha1.EventType) (result *v1alpha1.EventType, err error) { result = &v1alpha1.EventType{} err = c.client.Post(). + Namespace(c.ns). Resource("eventtypes"). Body(eventType). Do(). @@ -106,6 +112,7 @@ func (c *eventTypes) Create(eventType *v1alpha1.EventType) (result *v1alpha1.Eve func (c *eventTypes) Update(eventType *v1alpha1.EventType) (result *v1alpha1.EventType, err error) { result = &v1alpha1.EventType{} err = c.client.Put(). + Namespace(c.ns). Resource("eventtypes"). Name(eventType.Name). Body(eventType). @@ -120,6 +127,7 @@ func (c *eventTypes) Update(eventType *v1alpha1.EventType) (result *v1alpha1.Eve func (c *eventTypes) UpdateStatus(eventType *v1alpha1.EventType) (result *v1alpha1.EventType, err error) { result = &v1alpha1.EventType{} err = c.client.Put(). + Namespace(c.ns). Resource("eventtypes"). Name(eventType.Name). SubResource("status"). @@ -132,6 +140,7 @@ func (c *eventTypes) UpdateStatus(eventType *v1alpha1.EventType) (result *v1alph // Delete takes name of the eventType and deletes it. Returns an error if one occurs. func (c *eventTypes) Delete(name string, options *v1.DeleteOptions) error { return c.client.Delete(). + Namespace(c.ns). Resource("eventtypes"). Name(name). Body(options). @@ -142,6 +151,7 @@ func (c *eventTypes) Delete(name string, options *v1.DeleteOptions) error { // DeleteCollection deletes a collection of objects. func (c *eventTypes) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { return c.client.Delete(). + Namespace(c.ns). Resource("eventtypes"). VersionedParams(&listOptions, scheme.ParameterCodec). Body(options). @@ -153,6 +163,7 @@ func (c *eventTypes) DeleteCollection(options *v1.DeleteOptions, listOptions v1. func (c *eventTypes) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.EventType, err error) { result = &v1alpha1.EventType{} err = c.client.Patch(pt). + Namespace(c.ns). Resource("eventtypes"). SubResource(subresources...). Name(name). diff --git a/pkg/client/clientset/versioned/typed/eventing/v1alpha1/fake/fake_eventing_client.go b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/fake/fake_eventing_client.go index efb17feed5e..c14e2b271de 100644 --- a/pkg/client/clientset/versioned/typed/eventing/v1alpha1/fake/fake_eventing_client.go +++ b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/fake/fake_eventing_client.go @@ -40,8 +40,8 @@ func (c *FakeEventingV1alpha1) ClusterChannelProvisioners() v1alpha1.ClusterChan return &FakeClusterChannelProvisioners{c} } -func (c *FakeEventingV1alpha1) EventTypes() v1alpha1.EventTypeInterface { - return &FakeEventTypes{c} +func (c *FakeEventingV1alpha1) EventTypes(namespace string) v1alpha1.EventTypeInterface { + return &FakeEventTypes{c, namespace} } func (c *FakeEventingV1alpha1) Subscriptions(namespace string) v1alpha1.SubscriptionInterface { diff --git a/pkg/client/clientset/versioned/typed/eventing/v1alpha1/fake/fake_eventtype.go b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/fake/fake_eventtype.go index 2b914974d91..592074ffad5 100644 --- a/pkg/client/clientset/versioned/typed/eventing/v1alpha1/fake/fake_eventtype.go +++ b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/fake/fake_eventtype.go @@ -31,6 +31,7 @@ import ( // FakeEventTypes implements EventTypeInterface type FakeEventTypes struct { Fake *FakeEventingV1alpha1 + ns string } var eventtypesResource = schema.GroupVersionResource{Group: "eventing.knative.dev", Version: "v1alpha1", Resource: "eventtypes"} @@ -40,7 +41,8 @@ var eventtypesKind = schema.GroupVersionKind{Group: "eventing.knative.dev", Vers // 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 *v1alpha1.EventType, err error) { obj, err := c.Fake. - Invokes(testing.NewRootGetAction(eventtypesResource, name), &v1alpha1.EventType{}) + Invokes(testing.NewGetAction(eventtypesResource, c.ns, name), &v1alpha1.EventType{}) + if obj == nil { return nil, err } @@ -50,7 +52,8 @@ func (c *FakeEventTypes) Get(name string, options v1.GetOptions) (result *v1alph // List takes label and field selectors, and returns the list of EventTypes that match those selectors. func (c *FakeEventTypes) List(opts v1.ListOptions) (result *v1alpha1.EventTypeList, err error) { obj, err := c.Fake. - Invokes(testing.NewRootListAction(eventtypesResource, eventtypesKind, opts), &v1alpha1.EventTypeList{}) + Invokes(testing.NewListAction(eventtypesResource, eventtypesKind, c.ns, opts), &v1alpha1.EventTypeList{}) + if obj == nil { return nil, err } @@ -71,13 +74,15 @@ func (c *FakeEventTypes) List(opts v1.ListOptions) (result *v1alpha1.EventTypeLi // 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.NewRootWatchAction(eventtypesResource, opts)) + 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 *v1alpha1.EventType) (result *v1alpha1.EventType, err error) { obj, err := c.Fake. - Invokes(testing.NewRootCreateAction(eventtypesResource, eventType), &v1alpha1.EventType{}) + Invokes(testing.NewCreateAction(eventtypesResource, c.ns, eventType), &v1alpha1.EventType{}) + if obj == nil { return nil, err } @@ -87,7 +92,8 @@ func (c *FakeEventTypes) Create(eventType *v1alpha1.EventType) (result *v1alpha1 // 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 *v1alpha1.EventType) (result *v1alpha1.EventType, err error) { obj, err := c.Fake. - Invokes(testing.NewRootUpdateAction(eventtypesResource, eventType), &v1alpha1.EventType{}) + Invokes(testing.NewUpdateAction(eventtypesResource, c.ns, eventType), &v1alpha1.EventType{}) + if obj == nil { return nil, err } @@ -98,7 +104,8 @@ func (c *FakeEventTypes) Update(eventType *v1alpha1.EventType) (result *v1alpha1 // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). func (c *FakeEventTypes) UpdateStatus(eventType *v1alpha1.EventType) (*v1alpha1.EventType, error) { obj, err := c.Fake. - Invokes(testing.NewRootUpdateSubresourceAction(eventtypesResource, "status", eventType), &v1alpha1.EventType{}) + Invokes(testing.NewUpdateSubresourceAction(eventtypesResource, "status", c.ns, eventType), &v1alpha1.EventType{}) + if obj == nil { return nil, err } @@ -108,13 +115,14 @@ func (c *FakeEventTypes) UpdateStatus(eventType *v1alpha1.EventType) (*v1alpha1. // 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.NewRootDeleteAction(eventtypesResource, name), &v1alpha1.EventType{}) + Invokes(testing.NewDeleteAction(eventtypesResource, c.ns, name), &v1alpha1.EventType{}) + return err } // DeleteCollection deletes a collection of objects. func (c *FakeEventTypes) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { - action := testing.NewRootDeleteCollectionAction(eventtypesResource, listOptions) + action := testing.NewDeleteCollectionAction(eventtypesResource, c.ns, listOptions) _, err := c.Fake.Invokes(action, &v1alpha1.EventTypeList{}) return err @@ -123,7 +131,8 @@ func (c *FakeEventTypes) DeleteCollection(options *v1.DeleteOptions, listOptions // Patch applies the patch and returns the patched eventType. func (c *FakeEventTypes) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.EventType, err error) { obj, err := c.Fake. - Invokes(testing.NewRootPatchSubresourceAction(eventtypesResource, name, data, subresources...), &v1alpha1.EventType{}) + Invokes(testing.NewPatchSubresourceAction(eventtypesResource, c.ns, name, data, subresources...), &v1alpha1.EventType{}) + if obj == nil { return nil, err } diff --git a/pkg/client/informers/externalversions/eventing/v1alpha1/eventtype.go b/pkg/client/informers/externalversions/eventing/v1alpha1/eventtype.go index 3f1617c7c94..9e62ba5e723 100644 --- a/pkg/client/informers/externalversions/eventing/v1alpha1/eventtype.go +++ b/pkg/client/informers/externalversions/eventing/v1alpha1/eventtype.go @@ -41,32 +41,33 @@ type EventTypeInformer interface { 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, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { - return NewFilteredEventTypeInformer(client, resyncPeriod, indexers, nil) +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, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { +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 v1.ListOptions) (runtime.Object, error) { if tweakListOptions != nil { tweakListOptions(&options) } - return client.EventingV1alpha1().EventTypes().List(options) + return client.EventingV1alpha1().EventTypes(namespace).List(options) }, WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { if tweakListOptions != nil { tweakListOptions(&options) } - return client.EventingV1alpha1().EventTypes().Watch(options) + return client.EventingV1alpha1().EventTypes(namespace).Watch(options) }, }, &eventing_v1alpha1.EventType{}, @@ -76,7 +77,7 @@ func NewFilteredEventTypeInformer(client versioned.Interface, resyncPeriod time. } func (f *eventTypeInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { - return NewFilteredEventTypeInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) + return NewFilteredEventTypeInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) } func (f *eventTypeInformer) Informer() cache.SharedIndexInformer { diff --git a/pkg/client/informers/externalversions/eventing/v1alpha1/interface.go b/pkg/client/informers/externalversions/eventing/v1alpha1/interface.go index 81012e920e8..d272412d038 100644 --- a/pkg/client/informers/externalversions/eventing/v1alpha1/interface.go +++ b/pkg/client/informers/externalversions/eventing/v1alpha1/interface.go @@ -66,7 +66,7 @@ func (v *version) ClusterChannelProvisioners() ClusterChannelProvisionerInformer // EventTypes returns a EventTypeInformer. func (v *version) EventTypes() EventTypeInformer { - return &eventTypeInformer{factory: v.factory, tweakListOptions: v.tweakListOptions} + return &eventTypeInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} } // Subscriptions returns a SubscriptionInformer. diff --git a/pkg/client/listers/eventing/v1alpha1/eventtype.go b/pkg/client/listers/eventing/v1alpha1/eventtype.go index e3fb4b3c0d2..ffbdf6afdd5 100644 --- a/pkg/client/listers/eventing/v1alpha1/eventtype.go +++ b/pkg/client/listers/eventing/v1alpha1/eventtype.go @@ -29,8 +29,8 @@ import ( type EventTypeLister interface { // List lists all EventTypes in the indexer. List(selector labels.Selector) (ret []*v1alpha1.EventType, err error) - // Get retrieves the EventType from the index for a given name. - Get(name string) (*v1alpha1.EventType, error) + // EventTypes returns an object that can list and get EventTypes. + EventTypes(namespace string) EventTypeNamespaceLister EventTypeListerExpansion } @@ -52,9 +52,38 @@ func (s *eventTypeLister) List(selector labels.Selector) (ret []*v1alpha1.EventT return ret, err } -// Get retrieves the EventType from the index for a given name. -func (s *eventTypeLister) Get(name string) (*v1alpha1.EventType, error) { - obj, exists, err := s.indexer.GetByKey(name) +// 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 []*v1alpha1.EventType, err error) + // Get retrieves the EventType from the indexer for a given namespace and name. + Get(name string) (*v1alpha1.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 []*v1alpha1.EventType, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.EventType)) + }) + return ret, err +} + +// Get retrieves the EventType from the indexer for a given namespace and name. +func (s eventTypeNamespaceLister) Get(name string) (*v1alpha1.EventType, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) if err != nil { return nil, err } diff --git a/pkg/client/listers/eventing/v1alpha1/expansion_generated.go b/pkg/client/listers/eventing/v1alpha1/expansion_generated.go index 291586b3881..66326fa3477 100644 --- a/pkg/client/listers/eventing/v1alpha1/expansion_generated.go +++ b/pkg/client/listers/eventing/v1alpha1/expansion_generated.go @@ -42,6 +42,10 @@ type ClusterChannelProvisionerListerExpansion interface{} // EventTypeLister. type EventTypeListerExpansion interface{} +// EventTypeNamespaceListerExpansion allows custom methods to be added to +// EventTypeNamespaceLister. +type EventTypeNamespaceListerExpansion interface{} + // SubscriptionListerExpansion allows custom methods to be added to // SubscriptionLister. type SubscriptionListerExpansion interface{} From fc27ae2f7fc5750e8541e44a3cea8a6038c7efa6 Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Wed, 13 Mar 2019 13:43:13 -0700 Subject: [PATCH 147/221] adding create permission to ingress --- config/200-broker-clusterrole.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/config/200-broker-clusterrole.yaml b/config/200-broker-clusterrole.yaml index b1006375862..f5d6595029f 100644 --- a/config/200-broker-clusterrole.yaml +++ b/config/200-broker-clusterrole.yaml @@ -37,9 +37,10 @@ rules: - apiGroups: - eventing.knative.dev resources: - - event-types - - event-types/status + - eventtypes + - eventtypes/status verbs: - get - list - watch + - create From 2baca2e2b966ec609df7d47661992d256d780177 Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Wed, 13 Mar 2019 14:06:49 -0700 Subject: [PATCH 148/221] registry per namespace. Ingress policies working! --- b3.yaml | 6 ----- cmd/broker/ingress/main.go | 2 +- docs/registry/example_broker_policies.yaml | 24 ++++++++++++++++++ pkg/broker/ingress.go | 29 +++++++++++++--------- 4 files changed, 42 insertions(+), 19 deletions(-) delete mode 100644 b3.yaml create mode 100644 docs/registry/example_broker_policies.yaml diff --git a/b3.yaml b/b3.yaml deleted file mode 100644 index 1bd3e2af6f7..00000000000 --- a/b3.yaml +++ /dev/null @@ -1,6 +0,0 @@ -apiVersion: eventing.knative.dev/v1alpha1 -kind: Broker -metadata: - name: broker-test -spec: - ingressPolicy: allow_registered diff --git a/cmd/broker/ingress/main.go b/cmd/broker/ingress/main.go index c35bad2fa3e..8fe5f1f5f0f 100644 --- a/cmd/broker/ingress/main.go +++ b/cmd/broker/ingress/main.go @@ -157,7 +157,7 @@ func NewHandler(logger *zap.Logger, destination, policy string, client client.Cl func createReceiverFunction(f *Handler) func(provisioners.ChannelReference, *provisioners.Message) error { return func(c provisioners.ChannelReference, m *provisioners.Message) error { event := cloudEventFrom(m) - if f.ingressPolicy.AllowEvent(&event) { + if f.ingressPolicy.AllowEvent(&event, c.Namespace) { return f.dispatch(m) } return nil diff --git a/docs/registry/example_broker_policies.yaml b/docs/registry/example_broker_policies.yaml new file mode 100644 index 00000000000..f98b2275f0b --- /dev/null +++ b/docs/registry/example_broker_policies.yaml @@ -0,0 +1,24 @@ +apiVersion: eventing.knative.dev/v1alpha1 +kind: Broker +metadata: + name: broker-any +spec: + ingressPolicy: allow_any + +--- + +apiVersion: eventing.knative.dev/v1alpha1 +kind: Broker +metadata: + name: broker-registered +spec: + ingressPolicy: allow_registered + +--- + +apiVersion: eventing.knative.dev/v1alpha1 +kind: Broker +metadata: + name: broker-auto-create +spec: + ingressPolicy: auto_create diff --git a/pkg/broker/ingress.go b/pkg/broker/ingress.go index 6e7ae68bb14..6bc576d4f4e 100644 --- a/pkg/broker/ingress.go +++ b/pkg/broker/ingress.go @@ -48,7 +48,7 @@ var ( ) type IngressPolicy interface { - AllowEvent(event *cloudevents.Event) bool + AllowEvent(event *cloudevents.Event, namespace string) bool } type Any struct{} @@ -86,24 +86,27 @@ func newIngressPolicy(logger *zap.SugaredLogger, client client.Client, policy st } } -func (p *Any) AllowEvent(event *cloudevents.Event) bool { +func (p *Any) AllowEvent(event *cloudevents.Event, namespace string) bool { return true } -func (p *Registered) AllowEvent(event *cloudevents.Event) bool { - _, err := getEventType(p.client, event) +func (p *Registered) AllowEvent(event *cloudevents.Event, namespace string) bool { + _, err := getEventType(p.client, event, namespace) if k8serrors.IsNotFound(err) { - p.logger.Warnf("EventType not found, spec.type %q, %v", event.Type(), err) + p.logger.Warnf("EventType not found, rejecting spec.type %q, %v", event.Type(), err) + return false } else if err != nil { - p.logger.Errorf("Error retrieving EventType, spec.type %q, %v", event.Type(), err) + p.logger.Errorf("Error retrieving EventType, rejecting spec.type %q, %v", event.Type(), err) + return false } - return err != nil + return true } -func (p *AutoCreate) AllowEvent(event *cloudevents.Event) bool { - _, err := getEventType(p.client, event) +func (p *AutoCreate) AllowEvent(event *cloudevents.Event, namespace string) bool { + _, err := getEventType(p.client, event, namespace) if k8serrors.IsNotFound(err) { - eventType := makeEventType(event) + p.logger.Infof("EventType not found, creating spec.type %q", event.Type()) + eventType := makeEventType(event, namespace) err := p.client.Create(context.TODO(), eventType) if err != nil { p.logger.Errorf("Error creating EventType, spec.type %q, %v", event.Type(), err) @@ -114,8 +117,9 @@ func (p *AutoCreate) AllowEvent(event *cloudevents.Event) bool { return true } -func getEventType(c client.Client, event *cloudevents.Event) (*eventingv1alpha1.EventType, error) { +func getEventType(c client.Client, event *cloudevents.Event, namespace string) (*eventingv1alpha1.EventType, error) { opts := &client.ListOptions{ + Namespace: namespace, // Set Raw because if we need to get more than one page, then we will put the continue token // into opts.Raw.Continue. Raw: &metav1.ListOptions{}, @@ -147,11 +151,12 @@ func getEventType(c client.Client, event *cloudevents.Event) (*eventingv1alpha1. } // makeEventType generates, but does not create an EventType from the given cloudevents.Event. -func makeEventType(event *cloudevents.Event) *eventingv1alpha1.EventType { +func makeEventType(event *cloudevents.Event, namespace string) *eventingv1alpha1.EventType { cloudEventType := event.Type() return &eventingv1alpha1.EventType{ ObjectMeta: metav1.ObjectMeta{ GenerateName: fmt.Sprintf("%s-", toValidIdentifier(cloudEventType)), + Namespace: namespace, // TODO maybe some label? }, Spec: eventingv1alpha1.EventTypeSpec{ From ac3858732618983f55045eebc8a17f245b7ca4bb Mon Sep 17 00:00:00 2001 From: Adam Harwayne Date: Wed, 13 Mar 2019 14:54:16 -0700 Subject: [PATCH 149/221] Fix the bad merge by replacing logger.BaseLogger with logger.FormatLogger. --- test/e2e/broker_trigger_test.go | 78 ++++++++++++++++----------------- 1 file changed, 38 insertions(+), 40 deletions(-) diff --git a/test/e2e/broker_trigger_test.go b/test/e2e/broker_trigger_test.go index 6deacb0e8ab..127d3f5b180 100644 --- a/test/e2e/broker_trigger_test.go +++ b/test/e2e/broker_trigger_test.go @@ -55,28 +55,26 @@ type eventReceiver struct { // and sends different events to the broker's address. Finally, it verifies that only // the appropriate events are routed to the subscribers. func TestDefaultBrokerWithManyTriggers(t *testing.T) { - logger := logging.GetContextLogger("TestDefaultBrokerWithManyTriggers") - - clients, cleaner := Setup(t, logger) + clients, cleaner := Setup(t, t.Logf) // Verify namespace exists. - ns, cleanupNS := NamespaceExists(t, clients, logger) + ns, cleanupNS := NamespaceExists(t, clients, t.Logf) defer cleanupNS() - defer TearDown(clients, cleaner, logger) + defer TearDown(clients, cleaner, t.Logf) - logger.Infof("Labeling namespace %s", ns) + t.Logf("Labeling namespace %s", ns) // Label namespace so that it creates the default broker. - err := LabelNamespace(clients, logger, map[string]string{"knative-eventing-injection": "enabled"}) + err := LabelNamespace(clients, t.Logf, map[string]string{"knative-eventing-injection": "enabled"}) if err != nil { t.Fatalf("Error annotating namespace: %v", err) } - logger.Infof("Namespace %s annotated", ns) + t.Logf("Namespace %s annotated", ns) // Wait for default broker ready. - logger.Info("Waiting for default broker to be ready") + t.Logf("Waiting for default broker to be ready") defaultBroker := test.Broker(defaultBrokerName, ns) err = WaitForBrokerReady(clients, defaultBroker) if err != nil { @@ -85,7 +83,7 @@ func TestDefaultBrokerWithManyTriggers(t *testing.T) { defaultBrokerUrl := fmt.Sprintf("http://%s", defaultBroker.Status.Address.Hostname) - logger.Infof("Default broker ready: %q", defaultBrokerUrl) + t.Logf("Default broker ready: %q", defaultBrokerUrl) // These are the event types and sources that triggers will listen to, as well as the selectors // to set in the subscriber and services pods. @@ -96,43 +94,43 @@ func TestDefaultBrokerWithManyTriggers(t *testing.T) { {test.TypeAndSource{Type: eventType1, Source: eventSource1}, newSelector()}, } - logger.Info("Creating Subscriber pods") + t.Logf("Creating Subscriber pods") // Save the pods references in this map for later use. subscriberPods := make(map[string]*corev1.Pod, len(eventsToReceive)) for _, event := range eventsToReceive { subscriberPodName := name("dumper", event.typeAndSource.Type, event.typeAndSource.Source) subscriberPod := test.EventLoggerPod(subscriberPodName, ns, event.selector) - if err := CreatePod(clients, subscriberPod, logger, cleaner); err != nil { + if err := CreatePod(clients, subscriberPod, t.Logf, cleaner); err != nil { t.Fatalf("Error creating subscriber pod: %v", err) } subscriberPods[subscriberPodName] = subscriberPod } - logger.Info("Subscriber pods created") + t.Logf("Subscriber pods created") - logger.Info("Waiting for subscriber pods to become running") + t.Logf("Waiting for subscriber pods to become running") // Wait for all of the pods in the namespace to become running. - if err := WaitForAllPodsRunning(clients, logger, ns); err != nil { + if err := WaitForAllPodsRunning(clients, t.Logf, ns); err != nil { t.Fatalf("Error waiting for event logger pod to become running: %v", err) } - logger.Info("Subscriber pods running") + t.Logf("Subscriber pods running") - logger.Info("Creating Subscriber services") + t.Logf("Creating Subscriber services") for _, event := range eventsToReceive { subscriberSvcName := name("svc", event.typeAndSource.Type, event.typeAndSource.Source) service := test.Service(subscriberSvcName, ns, event.selector) - if err := CreateService(clients, service, logger, cleaner); err != nil { + if err := CreateService(clients, service, t.Logf, cleaner); err != nil { t.Fatalf("Error creating subscriber service: %v", err) } } - logger.Info("Subscriber services created") + t.Logf("Subscriber services created") - logger.Info("Creating Triggers") + t.Logf("Creating Triggers") for _, event := range eventsToReceive { triggerName := name("trigger", event.typeAndSource.Type, event.typeAndSource.Source) @@ -146,22 +144,22 @@ func TestDefaultBrokerWithManyTriggers(t *testing.T) { Broker(defaultBrokerName). SubscriberSvc(subscriberName). Build() - err := CreateTrigger(clients, trigger, logger, cleaner) + err := CreateTrigger(clients, trigger, t.Logf, cleaner) if err != nil { t.Fatalf("Error creating trigger: %v", err) } } - logger.Info("Triggers created") + t.Logf("Triggers created") - logger.Info("Waiting for triggers to become ready") + t.Logf("Waiting for triggers to become ready") // Wait for all of the triggers in the namespace to be ready. - if err := WaitForAllTriggersReady(clients, logger, ns); err != nil { + if err := WaitForAllTriggersReady(clients, t.Logf, ns); err != nil { t.Fatalf("Error waiting for triggers to become ready: %v", err) } - logger.Info("Triggers ready") + t.Logf("Triggers ready") // These are the event types and sources that will be send. eventsToSend := []test.TypeAndSource{ @@ -174,10 +172,10 @@ func TestDefaultBrokerWithManyTriggers(t *testing.T) { // We notice some crashLoopBacks in the filter and ingress pod creation. // We then delay the creation of the sender pods in order not to miss events. // TODO improve this - logger.Info("Waiting for filter and ingress pods to become running") + t.Logf("Waiting for filter and ingress pods to become running") time.Sleep(waitForFilterPodRunning) - logger.Info("Creating event sender pods") + t.Logf("Creating event sender pods") // Map to save the expected events per dumper so that we can verify the delivery. expectedEvents := make(map[string][]string) @@ -195,7 +193,7 @@ func TestDefaultBrokerWithManyTriggers(t *testing.T) { // Create sender pod. senderPodName := name("sender", eventToSend.Type, eventToSend.Source) senderPod := test.EventSenderPod(senderPodName, ns, defaultBrokerUrl, cloudEvent) - if err := CreatePod(clients, senderPod, logger, cleaner); err != nil { + if err := CreatePod(clients, senderPod, t.Logf, cleaner); err != nil { t.Fatalf("Error creating event sender pod: %v", err) } @@ -203,7 +201,7 @@ func TestDefaultBrokerWithManyTriggers(t *testing.T) { // to the expectedEvents/unexpectedEvents maps. for _, eventToReceive := range eventsToReceive { subscriberPodName := name("dumper", eventToReceive.typeAndSource.Type, eventToReceive.typeAndSource.Source) - if shouldExpectEvent(&eventToSend, &eventToReceive, logger) { + if shouldExpectEvent(&eventToSend, &eventToReceive, t.Logf) { expectedEvents[subscriberPodName] = append(expectedEvents[subscriberPodName], body) } else { unexpectedEvents[subscriberPodName] = append(unexpectedEvents[subscriberPodName], body) @@ -211,29 +209,29 @@ func TestDefaultBrokerWithManyTriggers(t *testing.T) { } } - logger.Info("Event sender pods created") + t.Logf("Event sender pods created") - logger.Info("Waiting for event sender pods to be running") + t.Logf("Waiting for event sender pods to be running") // Wait for all of them to be running. - if err := WaitForAllPodsRunning(clients, logger, ns); err != nil { + if err := WaitForAllPodsRunning(clients, t.Logf, ns); err != nil { t.Fatalf("Error waiting for event sender pod to become running: %v", err) } - logger.Info("Event sender pods running") + t.Logf("Event sender pods running") - logger.Info("Verifying events delivered to appropriate dumpers") + t.Logf("Verifying events delivered to appropriate dumpers") for _, event := range eventsToReceive { subscriberPodName := name("dumper", event.typeAndSource.Type, event.typeAndSource.Source) subscriberPod := subscriberPods[subscriberPodName] - logger.Infof("Dumper %q expecting %q", subscriberPodName, strings.Join(expectedEvents[subscriberPodName], ",")) - if err := WaitForLogContents(clients, logger, subscriberPodName, subscriberPod.Spec.Containers[0].Name, ns, expectedEvents[subscriberPodName]); err != nil { + t.Logf("Dumper %q expecting %q", subscriberPodName, strings.Join(expectedEvents[subscriberPodName], ",")) + if err := WaitForLogContents(clients, t.Logf, subscriberPodName, subscriberPod.Spec.Containers[0].Name, ns, expectedEvents[subscriberPodName]); err != nil { t.Fatalf("Event(s) not found in logs of subscriber pod %q: %v", subscriberPodName, err) } // At this point all the events should have been received in the pod. // We check whether we find unexpected events. If so, then we fail. - found, err := FindAnyLogContents(clients, logger, subscriberPodName, subscriberPod.Spec.Containers[0].Name, ns, unexpectedEvents[subscriberPodName]) + found, err := FindAnyLogContents(clients, t.Logf, subscriberPodName, subscriberPod.Spec.Containers[0].Name, ns, unexpectedEvents[subscriberPodName]) if err != nil { t.Fatalf("Failed querying to find log contents in pod %q: %v", subscriberPodName, err) } @@ -255,13 +253,13 @@ func newSelector() map[string]string { } // Checks whether we should expect to receive 'eventToSend' in 'eventReceiver' based on its type and source pattern. -func shouldExpectEvent(eventToSend *test.TypeAndSource, receiver *eventReceiver, logger *logging.BaseLogger) bool { +func shouldExpectEvent(eventToSend *test.TypeAndSource, receiver *eventReceiver, logf logging.FormatLogger) bool { if receiver.typeAndSource.Type != any && receiver.typeAndSource.Type != eventToSend.Type { - logger.Debugf("Event types mismatch, receive %s, send %s", receiver.typeAndSource.Type, eventToSend.Type) + logf("Event types mismatch, receive %s, send %s", receiver.typeAndSource.Type, eventToSend.Type) return false } if receiver.typeAndSource.Source != any && receiver.typeAndSource.Source != eventToSend.Source { - logger.Debugf("Event sources mismatch, receive %s, send %s", receiver.typeAndSource.Source, eventToSend.Source) + logf("Event sources mismatch, receive %s, send %s", receiver.typeAndSource.Source, eventToSend.Source) return false } return true From 542d4a781320bd13aa97980400b46b1e10e6a407 Mon Sep 17 00:00:00 2001 From: Adam Harwayne Date: Wed, 13 Mar 2019 15:54:26 -0700 Subject: [PATCH 150/221] Add extra columns when using kubectl get. --- config/300-broker.yaml | 3 +++ config/300-trigger.yaml | 6 ++++++ docs/broker/example_brokers.yaml | 2 +- docs/broker/example_triggers.yaml | 2 +- 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/config/300-broker.yaml b/config/300-broker.yaml index bb74cb7dd3f..b47e44068f0 100644 --- a/config/300-broker.yaml +++ b/config/300-broker.yaml @@ -37,3 +37,6 @@ spec: - name: Reason type: string JSONPath: ".status.conditions[?(@.type==\"Ready\")].reason" + - name: Hostname + type: string + JSONPath: .status.address.hostname diff --git a/config/300-trigger.yaml b/config/300-trigger.yaml index 122cdba1d67..fe6dc7cf094 100644 --- a/config/300-trigger.yaml +++ b/config/300-trigger.yaml @@ -37,3 +37,9 @@ spec: - name: Reason type: string JSONPath: ".status.conditions[?(@.type==\"Ready\")].reason" + - name: AssociatedBroker + type: string + JSONPath: .spec.broker + - name: SubscriberURI + type: string + JSONPath: .status.subscriberURI diff --git a/docs/broker/example_brokers.yaml b/docs/broker/example_brokers.yaml index d1cd9090fcb..2b2b87c4654 100644 --- a/docs/broker/example_brokers.yaml +++ b/docs/broker/example_brokers.yaml @@ -1,4 +1,4 @@ -# Copyright 2018 The Knative Authors +# Copyright 2019 The Knative Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/docs/broker/example_triggers.yaml b/docs/broker/example_triggers.yaml index af52fd4d9a2..5dd4bb7b169 100644 --- a/docs/broker/example_triggers.yaml +++ b/docs/broker/example_triggers.yaml @@ -1,4 +1,4 @@ -# Copyright 2018 The Knative Authors +# Copyright 2019 The Knative Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. From abf2495bd468378cf83af40de5d10ee7a1a2ff4e Mon Sep 17 00:00:00 2001 From: Adam Harwayne Date: Wed, 13 Mar 2019 16:04:33 -0700 Subject: [PATCH 151/221] MarkBrokerDoesNotExist --- pkg/apis/eventing/v1alpha1/trigger_types.go | 2 +- pkg/reconciler/v1alpha1/trigger/trigger.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/apis/eventing/v1alpha1/trigger_types.go b/pkg/apis/eventing/v1alpha1/trigger_types.go index 89e5b909078..b3742caf954 100644 --- a/pkg/apis/eventing/v1alpha1/trigger_types.go +++ b/pkg/apis/eventing/v1alpha1/trigger_types.go @@ -140,7 +140,7 @@ func (ts *TriggerStatus) MarkBrokerExists() { triggerCondSet.Manage(ts).MarkTrue(TriggerConditionBrokerExists) } -func (ts *TriggerStatus) MarkBrokerDoesNotExists() { +func (ts *TriggerStatus) MarkBrokerDoesNotExist() { triggerCondSet.Manage(ts).MarkFalse(TriggerConditionBrokerExists, "doesNotExist", "Broker does not exist") } diff --git a/pkg/reconciler/v1alpha1/trigger/trigger.go b/pkg/reconciler/v1alpha1/trigger/trigger.go index ff7bc56531e..d81cbda835d 100644 --- a/pkg/reconciler/v1alpha1/trigger/trigger.go +++ b/pkg/reconciler/v1alpha1/trigger/trigger.go @@ -223,7 +223,7 @@ func (r *reconciler) reconcile(ctx context.Context, t *v1alpha1.Trigger) error { b, err := r.getBroker(ctx, t) if err != nil { logging.FromContext(ctx).Error("Unable to get the Broker", zap.Error(err)) - t.Status.MarkBrokerDoesNotExists() + t.Status.MarkBrokerDoesNotExist() return err } t.Status.MarkBrokerExists() From bd5252d6814258a24c6212dc31b9c1fc772d555f Mon Sep 17 00:00:00 2001 From: Adam Harwayne Date: Wed, 13 Mar 2019 16:18:26 -0700 Subject: [PATCH 152/221] Rename extra columns. --- config/300-trigger.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/300-trigger.yaml b/config/300-trigger.yaml index fe6dc7cf094..65a15407433 100644 --- a/config/300-trigger.yaml +++ b/config/300-trigger.yaml @@ -37,9 +37,9 @@ spec: - name: Reason type: string JSONPath: ".status.conditions[?(@.type==\"Ready\")].reason" - - name: AssociatedBroker + - name: Broker type: string JSONPath: .spec.broker - - name: SubscriberURI + - name: Subscriber_URI type: string JSONPath: .status.subscriberURI From 68f5a7753a451b2de45bd14fe9b8eec5d8d4f36f Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Thu, 14 Mar 2019 10:56:31 -0700 Subject: [PATCH 153/221] cosmetic change --- pkg/broker/ingress.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/broker/ingress.go b/pkg/broker/ingress.go index 6bc576d4f4e..c4f469bd0d1 100644 --- a/pkg/broker/ingress.go +++ b/pkg/broker/ingress.go @@ -167,12 +167,13 @@ func makeEventType(event *cloudevents.Event, namespace string) *eventingv1alpha1 } } +// TODO some utility to also be used from eventing-sources. func toValidIdentifier(cloudEventType string) string { if msgs := validation.IsDNS1123Subdomain(cloudEventType); len(msgs) != 0 { // If it is not a valid DNS1123 name, make it a valid one. // TODO take care of size < 63, and starting and end indexes should be alphanumeric. cloudEventType = strings.ToLower(cloudEventType) - cloudEventType = validChars.ReplaceAllString(cloudEventType, "-") + cloudEventType = validChars.ReplaceAllString(cloudEventType, "") } return cloudEventType } From 5f9a5d4dc4fa972885f1d344d0cd9498fc2c1e90 Mon Sep 17 00:00:00 2001 From: Adam Harwayne Date: Thu, 14 Mar 2019 11:21:01 -0700 Subject: [PATCH 154/221] Replace the Trigger reconciler's in-memory map with a simple list, utilizing the fact that Controller Runtime already has the results of the List cached. --- pkg/reconciler/v1alpha1/trigger/trigger.go | 125 ++++++------------ .../v1alpha1/trigger/trigger_test.go | 26 ++-- 2 files changed, 46 insertions(+), 105 deletions(-) diff --git a/pkg/reconciler/v1alpha1/trigger/trigger.go b/pkg/reconciler/v1alpha1/trigger/trigger.go index d81cbda835d..bc10d996958 100644 --- a/pkg/reconciler/v1alpha1/trigger/trigger.go +++ b/pkg/reconciler/v1alpha1/trigger/trigger.go @@ -19,11 +19,9 @@ package trigger import ( "context" "fmt" - "sync" "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" "github.com/knative/eventing/pkg/logging" - "github.com/knative/eventing/pkg/provisioners" "github.com/knative/eventing/pkg/reconciler/names" "github.com/knative/eventing/pkg/reconciler/v1alpha1/broker" "github.com/knative/eventing/pkg/reconciler/v1alpha1/subscription" @@ -56,8 +54,6 @@ const ( // itself when creating events. controllerAgentName = "trigger-controller" - finalizerName = controllerAgentName - // Name of the corev1.Events emitted from the reconciliation process. triggerReconciled = "TriggerReconciled" triggerReconcileFailed = "TriggerReconcileFailed" @@ -66,20 +62,12 @@ const ( subscriptionCreateFailed = "SubscriptionCreateFailed" ) -var dummyValue struct{} - type reconciler struct { client client.Client restConfig *rest.Config dynamicClient dynamic.Interface recorder record.EventRecorder - triggersLock sync.RWMutex - // Contains the triggers that correspond to a particular broker. - // We use this to reconcile only the triggers that correspond to a certain broker. - // brokerNamespacedName -> triggerReconcileRequest -> dummy struct - triggers map[types.NamespacedName]map[reconcile.Request]struct{} - logger *zap.Logger } @@ -92,7 +80,6 @@ func ProvideController(mgr manager.Manager, logger *zap.Logger) (controller.Cont r := &reconciler{ recorder: mgr.GetRecorder(controllerAgentName), logger: logger, - triggers: make(map[types.NamespacedName]map[reconcile.Request]struct{}), } c, err := controller.New(controllerAgentName, mgr, controller.Options{ Reconciler: r, @@ -114,8 +101,9 @@ func ProvideController(mgr manager.Manager, logger *zap.Logger) (controller.Cont } } - // Watch for Broker changes. - if err = c.Watch(&source.Kind{Type: &v1alpha1.Broker{}}, &handler.EnqueueRequestsFromMapFunc{ToRequests: &mapAllTriggers{r}}); err != nil { + // Watch for Broker changes. E.g. if the Broker is deleted and recreated, we need to reconcile + // the Trigger again. + if err = c.Watch(&source.Kind{Type: &v1alpha1.Broker{}}, &handler.EnqueueRequestsFromMapFunc{ToRequests: &mapBrokerToTriggers{r: r}}); err != nil { return nil, err } @@ -125,24 +113,44 @@ func ProvideController(mgr manager.Manager, logger *zap.Logger) (controller.Cont return c, nil } -// mapAllTriggers maps Broker change notifications to Trigger reconcileRequests. -type mapAllTriggers struct { +// mapBrokerToTriggers maps Broker changes to all the Triggers that correspond to that Broker. +type mapBrokerToTriggers struct { r *reconciler } -func (m *mapAllTriggers) Map(o handler.MapObject) []reconcile.Request { - m.r.triggersLock.RLock() - defer m.r.triggersLock.RUnlock() - brokerNamespacedName := types.NamespacedName{Namespace: o.Meta.GetNamespace(), Name: o.Meta.GetName()} - triggersInBrokerNamespacedName := m.r.triggers[brokerNamespacedName] - if triggersInBrokerNamespacedName == nil { - return []reconcile.Request{} +func (b *mapBrokerToTriggers) Map(o handler.MapObject) []reconcile.Request { + ctx := context.Background() + triggers := make([]reconcile.Request, 0) + + opts := &client.ListOptions{ + Namespace: o.Meta.GetNamespace(), + // Set Raw because if we need to get more than one page, then we will put the continue token + // into opts.Raw.Continue. + Raw: &metav1.ListOptions{}, } - reqs := make([]reconcile.Request, 0, len(triggersInBrokerNamespacedName)) - for name := range triggersInBrokerNamespacedName { - reqs = append(reqs, name) + for { + tl := &v1alpha1.TriggerList{} + if err := b.r.client.List(ctx, opts, tl); err != nil { + b.r.logger.Error("Error listing Triggers when Broker changed. Some Triggers may not be reconciled.", zap.Error(err), zap.Any("broker", o)) + return triggers + } + + for _, t := range tl.Items { + if t.Spec.Broker == o.Meta.GetName() { + triggers = append(triggers, reconcile.Request{ + NamespacedName: types.NamespacedName{ + Namespace: t.Namespace, + Name: t.Name, + }, + }) + } + } + if tl.Continue != "" { + opts.Raw.Continue = tl.Continue + } else { + return triggers + } } - return reqs } func (r *reconciler) InjectClient(c client.Client) error { @@ -212,14 +220,9 @@ func (r *reconciler) reconcile(ctx context.Context, t *v1alpha1.Trigger) error { if t.DeletionTimestamp != nil { // Everything is cleaned up by the garbage collector. - r.removeFromTriggers(t) - provisioners.RemoveFinalizer(t, finalizerName) return nil } - provisioners.AddFinalizer(t, finalizerName) - r.AddToTriggers(t) - b, err := r.getBroker(ctx, t) if err != nil { logging.FromContext(ctx).Error("Unable to get the Broker", zap.Error(err)) @@ -266,58 +269,6 @@ func (r *reconciler) reconcile(ctx context.Context, t *v1alpha1.Trigger) error { return nil } -func (r *reconciler) AddToTriggers(t *v1alpha1.Trigger) { - name := reconcile.Request{ - NamespacedName: types.NamespacedName{ - Namespace: t.Namespace, - Name: t.Name, - }, - } - - brokerNamespacedName := types.NamespacedName{ - Namespace: t.Namespace, - Name: t.Spec.Broker} - - // We will be reconciling an already existing Trigger far more often than adding a new one, so - // check with a read lock before using the write lock. - r.triggersLock.RLock() - _, present := r.triggers[brokerNamespacedName][name] - r.triggersLock.RUnlock() - if present { - // Already present in the map. - return - } - - r.triggersLock.Lock() - triggersInBrokerNamespacedName := r.triggers[brokerNamespacedName] - if triggersInBrokerNamespacedName == nil { - r.triggers[brokerNamespacedName] = make(map[reconcile.Request]struct{}) - triggersInBrokerNamespacedName = r.triggers[brokerNamespacedName] - } - triggersInBrokerNamespacedName[name] = dummyValue - r.triggersLock.Unlock() -} - -func (r *reconciler) removeFromTriggers(t *v1alpha1.Trigger) { - name := reconcile.Request{ - NamespacedName: types.NamespacedName{ - Namespace: t.Namespace, - Name: t.Name, - }, - } - - brokerNamespacedName := types.NamespacedName{ - Namespace: t.Namespace, - Name: t.Spec.Broker} - - r.triggersLock.Lock() - triggersInBrokerNamespacedName := r.triggers[brokerNamespacedName] - if triggersInBrokerNamespacedName != nil { - delete(triggersInBrokerNamespacedName, name) - } - r.triggersLock.Unlock() -} - // updateStatus may in fact update the trigger's finalizers in addition to the status. func (r *reconciler) updateStatus(trigger *v1alpha1.Trigger) (*v1alpha1.Trigger, error) { ctx := context.TODO() @@ -440,7 +391,7 @@ func (r *reconciler) reconcileK8sService(ctx context.Context, t *v1alpha1.Trigge expected.Spec.ClusterIP = current.Spec.ClusterIP if !equality.Semantic.DeepDerivative(expected.Spec, current.Spec) { current.Spec = expected.Spec - err := r.client.Update(ctx, current) + err = r.client.Update(ctx, current) if err != nil { return nil, err } @@ -524,7 +475,7 @@ func (r *reconciler) reconcileVirtualService(ctx context.Context, t *v1alpha1.Tr expected := newVirtualService(t, svc) if !equality.Semantic.DeepDerivative(expected.Spec, virtualService.Spec) { virtualService.Spec = expected.Spec - err := r.client.Update(ctx, virtualService) + err = r.client.Update(ctx, virtualService) if err != nil { return nil, err } diff --git a/pkg/reconciler/v1alpha1/trigger/trigger_test.go b/pkg/reconciler/v1alpha1/trigger/trigger_test.go index 229546a684b..89828f4570f 100644 --- a/pkg/reconciler/v1alpha1/trigger/trigger_test.go +++ b/pkg/reconciler/v1alpha1/trigger/trigger_test.go @@ -22,30 +22,22 @@ import ( "fmt" "testing" - "github.com/knative/eventing/pkg/utils" - - "github.com/knative/eventing/pkg/provisioners" - - "github.com/knative/eventing/pkg/reconciler/names" - - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/util/intstr" - - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - "github.com/google/go-cmp/cmp" "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" + "github.com/knative/eventing/pkg/reconciler/names" controllertesting "github.com/knative/eventing/pkg/reconciler/testing" + "github.com/knative/eventing/pkg/utils" duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" istiov1alpha3 "github.com/knative/pkg/apis/istio/v1alpha3" "go.uber.org/zap" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/client-go/dynamic" "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/rest" + "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" ) @@ -77,12 +69,12 @@ var ( func init() { // Add types to scheme - v1alpha1.AddToScheme(scheme.Scheme) - istiov1alpha3.AddToScheme(scheme.Scheme) + _ = v1alpha1.AddToScheme(scheme.Scheme) + _ = istiov1alpha3.AddToScheme(scheme.Scheme) } func TestProvideController(t *testing.T) { - //TODO(grantr) This needs a mock of manager.Manager. Creating a manager + // TODO(grantr) This needs a mock of manager.Manager. Creating a manager // with a fake Config fails because the Manager tries to contact the // apiserver. @@ -455,7 +447,6 @@ func TestReconcile(t *testing.T) { restConfig: &rest.Config{}, recorder: recorder, logger: zap.NewNop(), - triggers: make(map[types.NamespacedName]map[reconcile.Request]struct{}), } tc.ReconcileKey = fmt.Sprintf("%s/%s", testNS, triggerName) tc.IgnoreTimes = true @@ -494,7 +485,6 @@ func makeTrigger() *v1alpha1.Trigger { func makeReadyTrigger() *v1alpha1.Trigger { t := makeTrigger() - provisioners.AddFinalizer(t, finalizerName) t.Status.InitializeConditions() t.Status.MarkBrokerExists() t.Status.SubscriberURI = fmt.Sprintf("http://%s.%s.svc.%s/", subscriberName, testNS, utils.GetClusterDomainName()) From b9a7d0f533b401b81d01c6768400f7a24716175b Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Thu, 14 Mar 2019 11:30:08 -0700 Subject: [PATCH 155/221] Accept v0.1 and v0.2 cloud events. Adding UTs. Updating initClient as well, removing unnecessary paging. --- pkg/broker/receiver.go | 46 ++++++++++++++-------------- pkg/broker/receiver_test.go | 60 ++++++++++++++++++++++--------------- 2 files changed, 60 insertions(+), 46 deletions(-) diff --git a/pkg/broker/receiver.go b/pkg/broker/receiver.go index b591a70ced2..c1d4b22578b 100644 --- a/pkg/broker/receiver.go +++ b/pkg/broker/receiver.go @@ -23,7 +23,6 @@ import ( eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" "github.com/knative/eventing/pkg/provisioners" "go.uber.org/zap" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/manager" @@ -86,25 +85,14 @@ func (r *Receiver) sendEvent(trigger provisioners.ChannelReference, message *pro return nil } -// Initialize the client. Mainly intended to load stuff in its cache. +// Initialize the client. Mainly intended to create the informer/indexer in order not to drop messages. func (r *Receiver) initClient() error { - // We list triggers so that we can load the client's cache. Otherwise, on receiving an event, it + // We list triggers so that we do not drop messages. Otherwise, on receiving an event, it // may not find the trigger and would return an error. - opts := &client.ListOptions{ - // Set Raw because if we need to get more than one page, then we will put the continue token - // into opts.Raw.Continue. - Raw: &metav1.ListOptions{}, - } - for { - tl := &eventingv1alpha1.TriggerList{} - if err := r.client.List(context.TODO(), opts, tl); err != nil { - return err - } - if tl.Continue != "" { - opts.Raw.Continue = tl.Continue - } else { - break - } + opts := &client.ListOptions{} + tl := &eventingv1alpha1.TriggerList{} + if err := r.client.List(context.TODO(), opts, tl); err != nil { + return err } return nil } @@ -128,13 +116,27 @@ func (r *Receiver) shouldSendMessage(ts *eventingv1alpha1.TriggerSpec, m *provis return false } filterType := ts.Filter.SourceAndType.Type - if filterType != eventingv1alpha1.TriggerAnyFilter && filterType != m.Headers["Ce-Eventtype"] { - r.logger.Debug("Wrong type", zap.String("trigger.spec.filter.sourceAndType.type", filterType), zap.String("message.type", m.Headers["Ce-Eventtype"])) + // TODO the inspection of Headers should be removed once we start using the cloud events SDK. + cloudEventType := "" + if et, ok := m.Headers["Ce-Eventtype"]; ok { + // cloud event spec v0.1. + cloudEventType = et + } else if et, ok := m.Headers["Ce-Type"]; ok { + // cloud event spec v0.2. + cloudEventType = et + } + if filterType != eventingv1alpha1.TriggerAnyFilter && filterType != cloudEventType { + r.logger.Debug("Wrong type", zap.String("trigger.spec.filter.sourceAndType.type", filterType), zap.String("message.type", cloudEventType)) return false } filterSource := ts.Filter.SourceAndType.Source - if filterSource != eventingv1alpha1.TriggerAnyFilter && filterSource != m.Headers["Ce-Source"] { - r.logger.Debug("Wrong source", zap.String("trigger.spec.filter.sourceAndType.source", filterSource), zap.String("message.source", m.Headers["Ce-Source"])) + cloudEventSource := "" + // cloud event spec v0.1 and v0.2. + if es, ok := m.Headers["Ce-Source"]; ok { + cloudEventSource = es + } + if filterSource != eventingv1alpha1.TriggerAnyFilter && filterSource != cloudEventSource { + r.logger.Debug("Wrong source", zap.String("trigger.spec.filter.sourceAndType.source", filterSource), zap.String("message.source", cloudEventSource)) return false } return true diff --git a/pkg/broker/receiver_test.go b/pkg/broker/receiver_test.go index 02a8518a351..81c4f9e9a8b 100644 --- a/pkg/broker/receiver_test.go +++ b/pkg/broker/receiver_test.go @@ -106,27 +106,31 @@ func TestReceiver(t *testing.T) { } for n, tc := range testCases { t.Run(n, func(t *testing.T) { - mr, _ := New( - zap.NewNop(), - fake.NewFakeClient(tc.initialState...)) - fd := &fakeDispatcher{ - err: tc.dispatchErr, - } - mr.dispatcher = fd - - resp := httptest.NewRecorder() - mr.newMessageReceiver().HandleRequest(resp, makeRequest()) - if tc.expectedErr { - if resp.Result().StatusCode >= 200 && resp.Result().StatusCode < 300 { - t.Errorf("Expected an error. Actual: %v", resp.Result()) + // Support cloud spec v0.1 and v0.2 requests. + requests := [2]*http.Request{makeV01Request(), makeV02Request()} + for _, request := range requests { + mr, _ := New( + zap.NewNop(), + fake.NewFakeClient(tc.initialState...)) + fd := &fakeDispatcher{ + err: tc.dispatchErr, } - } else { - if resp.Result().StatusCode < 200 || resp.Result().StatusCode >= 300 { - t.Errorf("Expected success. Actual: %v", resp.Result()) + mr.dispatcher = fd + + resp := httptest.NewRecorder() + mr.newMessageReceiver().HandleRequest(resp, request) + if tc.expectedErr { + if resp.Result().StatusCode >= 200 && resp.Result().StatusCode < 300 { + t.Errorf("Expected an error. Actual: %v", resp.Result()) + } + } else { + if resp.Result().StatusCode < 200 || resp.Result().StatusCode >= 300 { + t.Errorf("Expected success. Actual: %v", resp.Result()) + } + } + if tc.expectedDispatch != fd.requestReceived { + t.Errorf("Incorrect dispatch. Expected %v, Actual %v", tc.expectedDispatch, fd.requestReceived) } - } - if tc.expectedDispatch != fd.requestReceived { - t.Errorf("Incorrect dispatch. Expected %v, Actual %v", tc.expectedDispatch, fd.requestReceived) } }) } @@ -178,15 +182,15 @@ func makeTriggerWithoutSubscriberURI() *eventingv1alpha1.Trigger { return t } -func makeRequest() *http.Request { +func makeRequest(cloudEventVersionValue, eventTypeVersionValue, eventTypeKey, eventSourceKey string) *http.Request { req := httptest.NewRequest("POST", "/", strings.NewReader(``)) req.Host = fmt.Sprintf("%s.%s.triggers.%s", triggerName, testNS, utils.GetClusterDomainName()) eventAttributes := map[string]string{ - "CE-CloudEventsVersion": `"0.1"`, - "CE-EventType": eventType, - "CE-EventTypeVersion": `"1.0"`, - "CE-Source": eventSource, + "CE-CloudEventsVersion": cloudEventVersionValue, + eventTypeKey: eventType, + "CE-EventTypeVersion": eventTypeVersionValue, + eventSourceKey: eventSource, "CE-EventID": `"A234-1234-1234"`, "CE-EventTime": `"2018-04-05T17:31:00Z"`, "contentType": "text/xml", @@ -196,3 +200,11 @@ func makeRequest() *http.Request { } return req } + +func makeV01Request() *http.Request { + return makeRequest(`"0.1"`, `"1.0"`, "CE-EventType", "CE-Source") +} + +func makeV02Request() *http.Request { + return makeRequest(`"0.2"`, `"2.0"`, "CE-Type", "CE-Source") +} From 7d8ee9e29c2e2ef100466ae20a625c1a25172e61 Mon Sep 17 00:00:00 2001 From: Adam Harwayne Date: Thu, 14 Mar 2019 14:18:07 -0700 Subject: [PATCH 156/221] Change to resolve.SubscriberSpec(). --- pkg/reconciler/v1alpha1/trigger/trigger.go | 4 +- .../v1alpha1/trigger/trigger_test.go | 72 +++++++++++-------- 2 files changed, 45 insertions(+), 31 deletions(-) diff --git a/pkg/reconciler/v1alpha1/trigger/trigger.go b/pkg/reconciler/v1alpha1/trigger/trigger.go index bc10d996958..610224dc570 100644 --- a/pkg/reconciler/v1alpha1/trigger/trigger.go +++ b/pkg/reconciler/v1alpha1/trigger/trigger.go @@ -24,8 +24,8 @@ import ( "github.com/knative/eventing/pkg/logging" "github.com/knative/eventing/pkg/reconciler/names" "github.com/knative/eventing/pkg/reconciler/v1alpha1/broker" - "github.com/knative/eventing/pkg/reconciler/v1alpha1/subscription" "github.com/knative/eventing/pkg/utils" + "github.com/knative/eventing/pkg/utils/resolve" istiov1alpha3 "github.com/knative/pkg/apis/istio/v1alpha3" "go.uber.org/zap" corev1 "k8s.io/api/core/v1" @@ -237,7 +237,7 @@ func (r *reconciler) reconcile(ctx context.Context, t *v1alpha1.Trigger) error { return err } - subscriberURI, err := subscription.ResolveSubscriberSpec(ctx, r.client, r.dynamicClient, t.Namespace, t.Spec.Subscriber) + subscriberURI, err := resolve.SubscriberSpec(ctx, r.dynamicClient, t.Namespace, t.Spec.Subscriber) if err != nil { logging.FromContext(ctx).Error("Unable to get the Subscriber's URI", zap.Error(err)) return err diff --git a/pkg/reconciler/v1alpha1/trigger/trigger_test.go b/pkg/reconciler/v1alpha1/trigger/trigger_test.go index 89828f4570f..b65d27e9451 100644 --- a/pkg/reconciler/v1alpha1/trigger/trigger_test.go +++ b/pkg/reconciler/v1alpha1/trigger/trigger_test.go @@ -32,8 +32,8 @@ import ( "go.uber.org/zap" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/client-go/dynamic" "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/rest" @@ -214,13 +214,14 @@ func TestReconcile(t *testing.T) { makeBroker(), makeChannel(), }, - Mocks: controllertesting.Mocks{ - MockGets: []controllertesting.MockGet{ - func(_ client.Client, _ context.Context, key client.ObjectKey, obj runtime.Object) (controllertesting.MockHandled, error) { - if _, ok := obj.(*corev1.Service); ok { - return controllertesting.Handled, errors.New("test error resolving subscriber URI") + DynamicMocks: controllertesting.DynamicMocks{ + MockGets: []controllertesting.MockDynamicGet{ + func(ctx *controllertesting.MockDynamicContext, name string, options metav1.GetOptions, subresources ...string) (handled controllertesting.MockHandled, i *unstructured.Unstructured, e error) { + if ctx.Resource.Group == "" && ctx.Resource.Version == "v1" && ctx.Resource.Resource == "services" { + + return controllertesting.Handled, nil, errors.New("test error resolving subscriber URI") } - return controllertesting.Unhandled, nil + return controllertesting.Unhandled, nil, nil }, }, }, @@ -234,7 +235,9 @@ func TestReconcile(t *testing.T) { makeTrigger(), makeBroker(), makeChannel(), - makeSubscriberService(), + }, + Objects: []runtime.Object{ + makeSubscriberServiceAsUnstructured(), }, Mocks: controllertesting.Mocks{ MockCreates: []controllertesting.MockCreate{ @@ -256,9 +259,11 @@ func TestReconcile(t *testing.T) { makeTrigger(), makeBroker(), makeChannel(), - makeSubscriberService(), makeDifferentK8sService(), }, + Objects: []runtime.Object{ + makeSubscriberServiceAsUnstructured(), + }, Mocks: controllertesting.Mocks{ MockUpdates: []controllertesting.MockUpdate{ func(_ client.Client, _ context.Context, obj runtime.Object) (controllertesting.MockHandled, error) { @@ -279,9 +284,11 @@ func TestReconcile(t *testing.T) { makeTrigger(), makeBroker(), makeChannel(), - makeSubscriberService(), makeK8sService(), }, + Objects: []runtime.Object{ + makeSubscriberServiceAsUnstructured(), + }, Mocks: controllertesting.Mocks{ MockCreates: []controllertesting.MockCreate{ func(_ client.Client, _ context.Context, obj runtime.Object) (controllertesting.MockHandled, error) { @@ -302,10 +309,12 @@ func TestReconcile(t *testing.T) { makeTrigger(), makeBroker(), makeChannel(), - makeSubscriberService(), makeK8sService(), makeDifferentVirtualService(), }, + Objects: []runtime.Object{ + makeSubscriberServiceAsUnstructured(), + }, Mocks: controllertesting.Mocks{ MockUpdates: []controllertesting.MockUpdate{ func(_ client.Client, _ context.Context, obj runtime.Object) (controllertesting.MockHandled, error) { @@ -326,10 +335,12 @@ func TestReconcile(t *testing.T) { makeTrigger(), makeBroker(), makeChannel(), - makeSubscriberService(), makeK8sService(), makeVirtualService(), }, + Objects: []runtime.Object{ + makeSubscriberServiceAsUnstructured(), + }, Mocks: controllertesting.Mocks{ MockCreates: []controllertesting.MockCreate{ func(_ client.Client, _ context.Context, obj runtime.Object) (controllertesting.MockHandled, error) { @@ -350,11 +361,13 @@ func TestReconcile(t *testing.T) { makeTrigger(), makeBroker(), makeChannel(), - makeSubscriberService(), makeK8sService(), makeVirtualService(), makeDifferentSubscription(), }, + Objects: []runtime.Object{ + makeSubscriberServiceAsUnstructured(), + }, Mocks: controllertesting.Mocks{ MockDeletes: []controllertesting.MockDelete{ func(_ client.Client, _ context.Context, obj runtime.Object) (controllertesting.MockHandled, error) { @@ -375,11 +388,13 @@ func TestReconcile(t *testing.T) { makeTrigger(), makeBroker(), makeChannel(), - makeSubscriberService(), makeK8sService(), makeVirtualService(), makeDifferentSubscription(), }, + Objects: []runtime.Object{ + makeSubscriberServiceAsUnstructured(), + }, Mocks: controllertesting.Mocks{ MockCreates: []controllertesting.MockCreate{ func(_ client.Client, _ context.Context, obj runtime.Object) (controllertesting.MockHandled, error) { @@ -400,11 +415,13 @@ func TestReconcile(t *testing.T) { makeTrigger(), makeBroker(), makeChannel(), - makeSubscriberService(), makeK8sService(), makeVirtualService(), makeSameSubscription(), }, + Objects: []runtime.Object{ + makeSubscriberServiceAsUnstructured(), + }, Mocks: controllertesting.Mocks{ MockStatusUpdates: []controllertesting.MockStatusUpdate{ func(_ client.Client, _ context.Context, obj runtime.Object) (controllertesting.MockHandled, error) { @@ -425,11 +442,13 @@ func TestReconcile(t *testing.T) { makeTrigger(), makeBroker(), makeChannel(), - makeSubscriberService(), makeK8sService(), makeVirtualService(), makeSameSubscription(), }, + Objects: []runtime.Object{ + makeSubscriberServiceAsUnstructured(), + }, WantEvent: []corev1.Event{events[triggerReconciled]}, WantPresent: []runtime.Object{ makeReadyTrigger(), @@ -558,19 +577,14 @@ func makeDifferentChannel() *v1alpha1.Channel { return newChannel(fmt.Sprintf("%s-broker-different", brokerName)) } -func makeSubscriberService() *corev1.Service { - return &corev1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: testNS, - Name: subscriberName, - }, - Spec: corev1.ServiceSpec{ - Ports: []corev1.ServicePort{ - { - Name: "http", - Port: 80, - TargetPort: intstr.FromInt(8080), - }, +func makeSubscriberServiceAsUnstructured() *unstructured.Unstructured { + return &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "v1", + "kind": "Service", + "metadata": map[string]interface{}{ + "namespace": testNS, + "name": subscriberName, }, }, } From 99e7e4504ac71ac78b166d8d7fcb23edfa06531d Mon Sep 17 00:00:00 2001 From: Adam Harwayne Date: Thu, 14 Mar 2019 15:02:34 -0700 Subject: [PATCH 157/221] Remove restClient as it wasn't actually used. --- pkg/reconciler/v1alpha1/broker/broker.go | 6 ++---- pkg/reconciler/v1alpha1/broker/broker_test.go | 16 +++++++--------- pkg/reconciler/v1alpha1/namespace/namespace.go | 6 ++---- .../v1alpha1/namespace/namespace_test.go | 8 +++----- pkg/reconciler/v1alpha1/trigger/trigger.go | 2 -- pkg/reconciler/v1alpha1/trigger/trigger_test.go | 7 ------- 6 files changed, 14 insertions(+), 31 deletions(-) diff --git a/pkg/reconciler/v1alpha1/broker/broker.go b/pkg/reconciler/v1alpha1/broker/broker.go index afce06aebab..dda117d34de 100644 --- a/pkg/reconciler/v1alpha1/broker/broker.go +++ b/pkg/reconciler/v1alpha1/broker/broker.go @@ -36,7 +36,6 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/rest" "k8s.io/client-go/tools/record" "sigs.k8s.io/controller-runtime/pkg/client" runtimeclient "sigs.k8s.io/controller-runtime/pkg/client" @@ -58,9 +57,8 @@ const ( ) type reconciler struct { - client client.Client - restConfig *rest.Config - recorder record.EventRecorder + client client.Client + recorder record.EventRecorder logger *zap.Logger diff --git a/pkg/reconciler/v1alpha1/broker/broker_test.go b/pkg/reconciler/v1alpha1/broker/broker_test.go index 72de1f15252..42d4fa7958f 100644 --- a/pkg/reconciler/v1alpha1/broker/broker_test.go +++ b/pkg/reconciler/v1alpha1/broker/broker_test.go @@ -36,7 +36,6 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/client-go/kubernetes/scheme" - "k8s.io/client-go/rest" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" "sigs.k8s.io/controller-runtime/pkg/reconcile" @@ -70,11 +69,11 @@ var ( func init() { // Add types to scheme - v1alpha1.AddToScheme(scheme.Scheme) + _ = v1alpha1.AddToScheme(scheme.Scheme) } func TestProvideController(t *testing.T) { - //TODO(grantr) This needs a mock of manager.Manager. Creating a manager + // TODO(grantr) This needs a mock of manager.Manager. Creating a manager // with a fake Config fails because the Manager tries to contact the // apiserver. @@ -189,7 +188,7 @@ func TestReconcile(t *testing.T) { // differ from expected. // TODO uncomment the following line once our test framework supports searching for // GenerateName. - //makeDifferentChannel(), + // makeDifferentChannel(), }, WantEvent: []corev1.Event{ { @@ -535,7 +534,7 @@ func TestReconcile(t *testing.T) { WantPresent: []runtime.Object{ makeReadyBroker(), // TODO Uncomment makeChannel() when our test framework handles generateName. - //makeChannel(), + // makeChannel(), makeFilterDeployment(), makeFilterService(), makeIngressDeployment(), @@ -553,10 +552,9 @@ func TestReconcile(t *testing.T) { recorder := tc.GetEventRecorder() r := &reconciler{ - client: c, - restConfig: &rest.Config{}, - recorder: recorder, - logger: zap.NewNop(), + client: c, + recorder: recorder, + logger: zap.NewNop(), filterImage: filterImage, filterServiceAccountName: filterSA, diff --git a/pkg/reconciler/v1alpha1/namespace/namespace.go b/pkg/reconciler/v1alpha1/namespace/namespace.go index e5272122b13..cf427a4895f 100644 --- a/pkg/reconciler/v1alpha1/namespace/namespace.go +++ b/pkg/reconciler/v1alpha1/namespace/namespace.go @@ -31,7 +31,6 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/rest" "k8s.io/client-go/tools/record" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller" @@ -62,9 +61,8 @@ const ( ) type reconciler struct { - client client.Client - restConfig *rest.Config - recorder record.EventRecorder + client client.Client + recorder record.EventRecorder logger *zap.Logger } diff --git a/pkg/reconciler/v1alpha1/namespace/namespace_test.go b/pkg/reconciler/v1alpha1/namespace/namespace_test.go index 7c1b9e2769c..87e522fe010 100644 --- a/pkg/reconciler/v1alpha1/namespace/namespace_test.go +++ b/pkg/reconciler/v1alpha1/namespace/namespace_test.go @@ -31,7 +31,6 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/kubernetes/scheme" - "k8s.io/client-go/rest" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" "sigs.k8s.io/controller-runtime/pkg/handler" @@ -241,10 +240,9 @@ func TestReconcile(t *testing.T) { recorder := tc.GetEventRecorder() r := &reconciler{ - client: c, - restConfig: &rest.Config{}, - recorder: recorder, - logger: zap.NewNop(), + client: c, + recorder: recorder, + logger: zap.NewNop(), } tc.ReconcileKey = fmt.Sprintf("%s/%s", "", testNS) tc.IgnoreTimes = true diff --git a/pkg/reconciler/v1alpha1/trigger/trigger.go b/pkg/reconciler/v1alpha1/trigger/trigger.go index 610224dc570..60d96e39862 100644 --- a/pkg/reconciler/v1alpha1/trigger/trigger.go +++ b/pkg/reconciler/v1alpha1/trigger/trigger.go @@ -64,7 +64,6 @@ const ( type reconciler struct { client client.Client - restConfig *rest.Config dynamicClient dynamic.Interface recorder record.EventRecorder @@ -159,7 +158,6 @@ func (r *reconciler) InjectClient(c client.Client) error { } func (r *reconciler) InjectConfig(c *rest.Config) error { - r.restConfig = c var err error r.dynamicClient, err = dynamic.NewForConfig(c) return err diff --git a/pkg/reconciler/v1alpha1/trigger/trigger_test.go b/pkg/reconciler/v1alpha1/trigger/trigger_test.go index b65d27e9451..ea05130025a 100644 --- a/pkg/reconciler/v1alpha1/trigger/trigger_test.go +++ b/pkg/reconciler/v1alpha1/trigger/trigger_test.go @@ -22,7 +22,6 @@ import ( "fmt" "testing" - "github.com/google/go-cmp/cmp" "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" "github.com/knative/eventing/pkg/reconciler/names" controllertesting "github.com/knative/eventing/pkg/reconciler/testing" @@ -120,11 +119,6 @@ func TestInjectConfig(t *testing.T) { t.Fatalf("Unexpected error injecting the config: %v", err) } - gotCfg := r.restConfig - if diff := cmp.Diff(wantCfg, gotCfg); diff != "" { - t.Errorf("Unexpected config (-want, +got): %v", diff) - } - wantDynClient, err := dynamic.NewForConfig(wantCfg) if err != nil { t.Fatalf("Unexpected error generating dynamic client: %v", err) @@ -463,7 +457,6 @@ func TestReconcile(t *testing.T) { r := &reconciler{ client: c, dynamicClient: dc, - restConfig: &rest.Config{}, recorder: recorder, logger: zap.NewNop(), } From 24d760392bd22e768b4fdf30edad91704ed84a2c Mon Sep 17 00:00:00 2001 From: Adam Harwayne Date: Thu, 14 Mar 2019 15:18:37 -0700 Subject: [PATCH 158/221] Only reconcile the Namespace if the specific resource we care about changes. --- .../v1alpha1/namespace/namespace.go | 37 +++++++++++++------ .../v1alpha1/namespace/namespace_test.go | 8 ++-- 2 files changed, 31 insertions(+), 14 deletions(-) diff --git a/pkg/reconciler/v1alpha1/namespace/namespace.go b/pkg/reconciler/v1alpha1/namespace/namespace.go index cf427a4895f..8e065de6b93 100644 --- a/pkg/reconciler/v1alpha1/namespace/namespace.go +++ b/pkg/reconciler/v1alpha1/namespace/namespace.go @@ -89,9 +89,19 @@ func ProvideController(mgr manager.Manager, logger *zap.Logger) (controller.Cont return nil, err } - // Watch all the resources that this reconciler reconciles. - for _, t := range []runtime.Object{&corev1.ServiceAccount{}, &rbacv1.RoleBinding{}, &v1alpha1.Broker{}} { - err = c.Watch(&source.Kind{Type: t}, &handler.EnqueueRequestsFromMapFunc{ToRequests: &namespaceMapper{}}) + // Watch all the resources that this reconciler reconciles. This is a map from resource type to + // the name of the resource of that type we care about (i.e. only if the resource of the given + // type and with the given name changes, do we reconcile the Namespace). + resources := map[runtime.Object]string{ + &corev1.ServiceAccount{}: brokerFilterSA, + &rbacv1.RoleBinding{}: brokerFilterRB, + &v1alpha1.Broker{}: defaultBroker, + } + for t, n := range resources { + nm := &namespaceMapper{ + name: n, + } + err = c.Watch(&source.Kind{Type: t}, &handler.EnqueueRequestsFromMapFunc{ToRequests: nm}) if err != nil { return nil, err } @@ -100,19 +110,24 @@ func ProvideController(mgr manager.Manager, logger *zap.Logger) (controller.Cont return c, nil } -type namespaceMapper struct{} +type namespaceMapper struct { + name string +} var _ handler.Mapper = &namespaceMapper{} -func (namespaceMapper) Map(o handler.MapObject) []reconcile.Request { - return []reconcile.Request{ - { - NamespacedName: types.NamespacedName{ - Namespace: "", - Name: o.Meta.GetNamespace(), +func (m *namespaceMapper) Map(o handler.MapObject) []reconcile.Request { + if o.Meta.GetName() == m.name { + return []reconcile.Request{ + { + NamespacedName: types.NamespacedName{ + Namespace: "", + Name: o.Meta.GetNamespace(), + }, }, - }, + } } + return []reconcile.Request{} } func (r *reconciler) InjectClient(c client.Client) error { diff --git a/pkg/reconciler/v1alpha1/namespace/namespace_test.go b/pkg/reconciler/v1alpha1/namespace/namespace_test.go index 87e522fe010..be60e4a9828 100644 --- a/pkg/reconciler/v1alpha1/namespace/namespace_test.go +++ b/pkg/reconciler/v1alpha1/namespace/namespace_test.go @@ -60,11 +60,11 @@ var ( func init() { // Add types to scheme - v1alpha1.AddToScheme(scheme.Scheme) + _ = v1alpha1.AddToScheme(scheme.Scheme) } func TestProvideController(t *testing.T) { - //TODO(grantr) This needs a mock of manager.Manager. Creating a manager + // TODO(grantr) This needs a mock of manager.Manager. Creating a manager // with a fake Config fails because the Manager tries to contact the // apiserver. @@ -100,7 +100,9 @@ func TestInjectClient(t *testing.T) { } func TestNamespaceMapper_Map(t *testing.T) { - m := &namespaceMapper{} + m := &namespaceMapper{ + name: makeBroker().Name, + } req := handler.MapObject{ Meta: makeBroker().GetObjectMeta(), From 326d9f60963b4c79d4fae4828613c3e59254db66 Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Thu, 14 Mar 2019 15:20:39 -0700 Subject: [PATCH 159/221] changing origin to from --- cmd/broker/ingress/main.go | 6 +++--- config/300-eventtype.yaml | 4 ++-- pkg/apis/eventing/v1alpha1/eventtype_types.go | 2 +- pkg/broker/ingress.go | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/cmd/broker/ingress/main.go b/cmd/broker/ingress/main.go index 8fe5f1f5f0f..15989c8f488 100644 --- a/cmd/broker/ingress/main.go +++ b/cmd/broker/ingress/main.go @@ -53,7 +53,7 @@ const ( v2EventType = "Ce-Type" v2EventSource = "Ce-Source" // Extension attribute. - eventOrigin = "Ce-Origin" + eventFrom = "Ce-From" ) var ( @@ -196,8 +196,8 @@ func cloudEventFrom(m *provisioners.Message) cloudevents.Event { event := cloudevents.Event{} // TODO better way to set extensions. var extensions map[string]interface{} - if origin, ok := m.Headers[eventOrigin]; ok { - extensions[eventOrigin] = origin + if origin, ok := m.Headers[eventFrom]; ok { + extensions[eventFrom] = origin } if eventType, ok := m.Headers[v2EventType]; ok { event.Context = cloudevents.EventContextV02{ diff --git a/config/300-eventtype.yaml b/config/300-eventtype.yaml index a36b138bf48..9cbc4808eb8 100644 --- a/config/300-eventtype.yaml +++ b/config/300-eventtype.yaml @@ -33,9 +33,9 @@ spec: - name: Type type: string JSONPath: ".spec.type" - - name: Origin + - name: From type: string - JSONPath: ".spec.origin" + JSONPath: ".spec.from" - name: Schema type: string JSONPath: ".spec.schema" diff --git a/pkg/apis/eventing/v1alpha1/eventtype_types.go b/pkg/apis/eventing/v1alpha1/eventtype_types.go index 3bc01200598..68d183b457e 100644 --- a/pkg/apis/eventing/v1alpha1/eventtype_types.go +++ b/pkg/apis/eventing/v1alpha1/eventtype_types.go @@ -62,7 +62,7 @@ type EventTypeSpec struct { // Type refers to the cloud event type. Type string `json:"type,omitempty"` // +optional - Origin string `json:"origin,omitempty"` + From string `json:"from,omitempty"` // +optional Schema string `json:"schema,omitempty"` } diff --git a/pkg/broker/ingress.go b/pkg/broker/ingress.go index c4f469bd0d1..6dea724bd70 100644 --- a/pkg/broker/ingress.go +++ b/pkg/broker/ingress.go @@ -161,8 +161,8 @@ func makeEventType(event *cloudevents.Event, namespace string) *eventingv1alpha1 }, Spec: eventingv1alpha1.EventTypeSpec{ Type: cloudEventType, - Origin: "", // event.Extensions("Origin") - Schema: "", // event.Extensions("Schema") + From: "", // event.Extensions("from") + Schema: "", // event.Extensions("schema") }, } } From c27bf220fc3244956c82ed07e1ff25c150e3ebad Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Thu, 14 Mar 2019 15:24:35 -0700 Subject: [PATCH 160/221] lowercase --- pkg/broker/receiver_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/broker/receiver_test.go b/pkg/broker/receiver_test.go index 81c4f9e9a8b..d98edb6be45 100644 --- a/pkg/broker/receiver_test.go +++ b/pkg/broker/receiver_test.go @@ -206,5 +206,5 @@ func makeV01Request() *http.Request { } func makeV02Request() *http.Request { - return makeRequest(`"0.2"`, `"2.0"`, "CE-Type", "CE-Source") + return makeRequest(`"0.2"`, `"2.0"`, "ce-type", "ce-source") } From a5fa2276f8871bf4162ecf17b6549bc54cd23661 Mon Sep 17 00:00:00 2001 From: nachocano Date: Mon, 18 Mar 2019 16:59:45 -0700 Subject: [PATCH 161/221] Merge remote-tracking branch 'upstream/master' into registry-namespace # Conflicts: # cmd/broker/ingress/main.go # cmd/webhook/main.go # config/200-broker-clusterrole.yaml # config/500-controller.yaml # pkg/apis/eventing/v1alpha1/broker_types.go # pkg/apis/eventing/v1alpha1/register.go # pkg/reconciler/v1alpha1/broker/broker.go # pkg/reconciler/v1alpha1/broker/resources/ingress.go # pkg/reconciler/v1alpha1/namespace/namespace.go # pkg/reconciler/v1alpha1/trigger/trigger.go --- pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go index 5a974f5802a..a53904d8238 100644 --- a/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go @@ -444,7 +444,7 @@ func (in *EventTypeStatus) DeepCopyInto(out *EventTypeStatus) { *out = *in if in.Conditions != nil { in, out := &in.Conditions, &out.Conditions - *out = make(duck_v1alpha1.Conditions, len(*in)) + *out = make(apis_duck_v1alpha1.Conditions, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } From b99266b834063533bd5df5ae4b11b9d91e729bf2 Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Wed, 20 Mar 2019 23:52:05 -0700 Subject: [PATCH 162/221] updating event type to include broker --- cmd/broker/ingress/main.go | 21 ++++++------------- pkg/apis/eventing/v1alpha1/eventtype_types.go | 7 ++++--- pkg/broker/ingress.go | 8 ++++--- 3 files changed, 15 insertions(+), 21 deletions(-) diff --git a/cmd/broker/ingress/main.go b/cmd/broker/ingress/main.go index 34daa8e013b..c3d971d04d9 100644 --- a/cmd/broker/ingress/main.go +++ b/cmd/broker/ingress/main.go @@ -50,8 +50,6 @@ const ( v2EventId = "Ce-Id" v2EventType = "Ce-Type" v2EventSource = "Ce-Source" - // Extension attribute. - eventFrom = "Ce-From" ) var ( @@ -192,24 +190,17 @@ func (r *runnableServer) Start(<-chan struct{}) error { // TODO this should be removed once we update the interfaces and start using cloudevents.Event instead of Message. func cloudEventFrom(m *provisioners.Message) cloudevents.Event { event := cloudevents.Event{} - // TODO better way to set extensions. - var extensions map[string]interface{} - if origin, ok := m.Headers[eventFrom]; ok { - extensions[eventFrom] = origin - } if eventType, ok := m.Headers[v2EventType]; ok { event.Context = cloudevents.EventContextV02{ - ID: m.Headers[v2EventId], - Type: eventType, - Source: *types.ParseURLRef(v2EventSource), - Extensions: extensions, + ID: m.Headers[v2EventId], + Type: eventType, + Source: *types.ParseURLRef(v2EventSource), }.AsV02() } else { event.Context = cloudevents.EventContextV01{ - EventID: m.Headers[v1EventId], - EventType: m.Headers[v1EventType], - Source: *types.ParseURLRef(v1EventSource), - Extensions: extensions, + EventID: m.Headers[v1EventId], + EventType: m.Headers[v1EventType], + Source: *types.ParseURLRef(v1EventSource), }.AsV01() } return event diff --git a/pkg/apis/eventing/v1alpha1/eventtype_types.go b/pkg/apis/eventing/v1alpha1/eventtype_types.go index 68d183b457e..bf770ba5453 100644 --- a/pkg/apis/eventing/v1alpha1/eventtype_types.go +++ b/pkg/apis/eventing/v1alpha1/eventtype_types.go @@ -58,13 +58,14 @@ type EventTypeSpec struct { // +optional DeprecatedGeneration int64 `json:"generation,omitempty"` - // TODO these attributes should be updated once we clarify the UX. - // Type refers to the cloud event type. + // TODO these attributes may need to be updated once we agree on the object model. Type string `json:"type,omitempty"` // +optional - From string `json:"from,omitempty"` + Source string `json:"source,omitempty"` // +optional Schema string `json:"schema,omitempty"` + // TODO sink or broker? + Broker string `json:"broker,omitempty"` } var eventTypeCondSet = duckv1alpha1.NewLivingConditionSet(EventTypeConditionReady) diff --git a/pkg/broker/ingress.go b/pkg/broker/ingress.go index 6dea724bd70..b4f00713788 100644 --- a/pkg/broker/ingress.go +++ b/pkg/broker/ingress.go @@ -157,12 +157,14 @@ func makeEventType(event *cloudevents.Event, namespace string) *eventingv1alpha1 ObjectMeta: metav1.ObjectMeta{ GenerateName: fmt.Sprintf("%s-", toValidIdentifier(cloudEventType)), Namespace: namespace, - // TODO maybe some label? + // TODO add broker label }, Spec: eventingv1alpha1.EventTypeSpec{ Type: cloudEventType, - From: "", // event.Extensions("from") - Schema: "", // event.Extensions("schema") + Source: "", // event.Source() + Schema: "", // event.Schema() + // TODO set it as env variable in the ingress. + Broker: "", }, } } From 61af012377ed3606befa220cc46db9001716f92e Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Thu, 21 Mar 2019 00:17:18 -0700 Subject: [PATCH 163/221] additional columns --- config/300-eventtype.yaml | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/config/300-eventtype.yaml b/config/300-eventtype.yaml index 9cbc4808eb8..26ce91117a5 100644 --- a/config/300-eventtype.yaml +++ b/config/300-eventtype.yaml @@ -23,9 +23,9 @@ spec: plural: eventtypes singular: eventtype categories: - - all - - knative - - eventing + - all + - knative + - eventing scope: Namespaced subresources: status: {} @@ -33,9 +33,12 @@ spec: - name: Type type: string JSONPath: ".spec.type" - - name: From + - name: Source type: string - JSONPath: ".spec.from" + JSONPath: ".spec.source" + - name: Broker + type: string + JSONPath: ".spec.broker" - name: Schema type: string JSONPath: ".spec.schema" From 8dd52925179ff77d1c93d2712ced44f92b130e09 Mon Sep 17 00:00:00 2001 From: nachocano Date: Thu, 21 Mar 2019 11:59:56 -0700 Subject: [PATCH 164/221] just TODOs --- pkg/broker/ingress.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pkg/broker/ingress.go b/pkg/broker/ingress.go index b4f00713788..17cdc9014c3 100644 --- a/pkg/broker/ingress.go +++ b/pkg/broker/ingress.go @@ -120,6 +120,7 @@ func (p *AutoCreate) AllowEvent(event *cloudevents.Event, namespace string) bool func getEventType(c client.Client, event *cloudevents.Event, namespace string) (*eventingv1alpha1.EventType, error) { opts := &client.ListOptions{ Namespace: namespace, + // TODO add label selector on broker name. // Set Raw because if we need to get more than one page, then we will put the continue token // into opts.Raw.Continue. Raw: &metav1.ListOptions{}, @@ -127,8 +128,6 @@ func getEventType(c client.Client, event *cloudevents.Event, namespace string) ( ctx := context.TODO() - // TODO this is very inefficient, we need to somehow select with a fieldSelector on spec.type, - // but it is not supported. for { el := &eventingv1alpha1.EventTypeList{} err := c.List(ctx, opts, el) @@ -136,7 +135,7 @@ func getEventType(c client.Client, event *cloudevents.Event, namespace string) ( return nil, err } for _, e := range el.Items { - // TODO ask Scott for better queries to get extensions. + // TODO update cloud events version once it is merged // e.Spec.Origin == event.Extensions("Origin") && e.Spec.Schema == event.Extensions("Schema") if e.Spec.Type == event.Type() { return &e, nil From 9ca02c26b7bfd57fbcd140d9c47b359d1d788d11 Mon Sep 17 00:00:00 2001 From: nachocano Date: Thu, 21 Mar 2019 12:51:26 -0700 Subject: [PATCH 165/221] adding some TODOs --- cmd/broker/ingress/main.go | 2 ++ docs/registry/example_eventtype.yaml | 9 +++++---- pkg/apis/eventing/v1alpha1/eventtype_types.go | 2 +- pkg/broker/ingress.go | 6 ++++-- 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/cmd/broker/ingress/main.go b/cmd/broker/ingress/main.go index c3d971d04d9..fb5de0308ef 100644 --- a/cmd/broker/ingress/main.go +++ b/cmd/broker/ingress/main.go @@ -44,6 +44,7 @@ const ( POLICY = "POLICY" // TODO should remove this constants once we start using cloudevents-sdk properly. + // Waiting for https://github.com/knative/eventing/pull/933 v1EventId = "Ce-Eventid" v1EventType = "Ce-Eventtype" v1EventSource = "Ce-Source" @@ -188,6 +189,7 @@ func (r *runnableServer) Start(<-chan struct{}) error { } // TODO this should be removed once we update the interfaces and start using cloudevents.Event instead of Message. +// Waiting for https://github.com/knative/eventing/pull/933 func cloudEventFrom(m *provisioners.Message) cloudevents.Event { event := cloudevents.Event{} if eventType, ok := m.Headers[v2EventType]; ok { diff --git a/docs/registry/example_eventtype.yaml b/docs/registry/example_eventtype.yaml index 82f6f5805ff..75f9ded34a1 100644 --- a/docs/registry/example_eventtype.yaml +++ b/docs/registry/example_eventtype.yaml @@ -2,9 +2,10 @@ apiVersion: eventing.knative.dev/v1alpha1 kind: EventType metadata: # advisory - name: dev.knative.source.bitbucket.repo-push + name: repopush spec: # authoritative - type: dev.knative.source.bitbucket.repo:push - origin: bitbucket.org - schema: https://api.bitbucket.org/2.0/schemas/repo/push + type: repo:push + source: user/repo + schema: http://schemas/repo/push + broker: broker-any diff --git a/pkg/apis/eventing/v1alpha1/eventtype_types.go b/pkg/apis/eventing/v1alpha1/eventtype_types.go index bf770ba5453..f742a06299c 100644 --- a/pkg/apis/eventing/v1alpha1/eventtype_types.go +++ b/pkg/apis/eventing/v1alpha1/eventtype_types.go @@ -64,7 +64,7 @@ type EventTypeSpec struct { Source string `json:"source,omitempty"` // +optional Schema string `json:"schema,omitempty"` - // TODO sink or broker? + // TODO sink or broker? string or ref? Broker string `json:"broker,omitempty"` } diff --git a/pkg/broker/ingress.go b/pkg/broker/ingress.go index 17cdc9014c3..ea1a9650ce0 100644 --- a/pkg/broker/ingress.go +++ b/pkg/broker/ingress.go @@ -157,12 +157,14 @@ func makeEventType(event *cloudevents.Event, namespace string) *eventingv1alpha1 GenerateName: fmt.Sprintf("%s-", toValidIdentifier(cloudEventType)), Namespace: namespace, // TODO add broker label + // Waiting on https://github.com/knative/eventing/pull/937 + // which passes the broker name as an env variable. }, Spec: eventingv1alpha1.EventTypeSpec{ Type: cloudEventType, Source: "", // event.Source() - Schema: "", // event.Schema() - // TODO set it as env variable in the ingress. + Schema: "", // event.SchemaURL() + // Waiting on https://github.com/knative/eventing/pull/937 Broker: "", }, } From b500d30e10f51d5cf0e3b270e70490fdc21a8b3b Mon Sep 17 00:00:00 2001 From: nachocano Date: Thu, 21 Mar 2019 12:57:54 -0700 Subject: [PATCH 166/221] Adding TODOs, updating cloudevents after my change --- Gopkg.lock | 5 +- Gopkg.toml | 4 +- pkg/apis/eventing/v1alpha1/eventtype_types.go | 1 + pkg/broker/ingress.go | 10 +-- .../sdk-go/pkg/cloudevents/client/client.go | 22 ++++-- .../pkg/cloudevents/client/defaulters.go | 6 ++ .../pkg/cloudevents/client/observability.go | 37 ++++++---- .../sdk-go/pkg/cloudevents/client/options.go | 1 + .../sdk-go/pkg/cloudevents/codec/jsoncodec.go | 12 ++-- .../pkg/cloudevents/codec/observability.go | 49 ++++++++----- .../sdk-go/pkg/cloudevents/datacodec/codec.go | 4 +- .../pkg/cloudevents/datacodec/json/data.go | 4 +- .../pkg/cloudevents/datacodec/json/doc.go | 2 +- .../datacodec/json/observability.go | 31 +++++--- .../cloudevents/datacodec/observability.go | 31 +++++--- .../pkg/cloudevents/datacodec/xml/data.go | 4 +- .../pkg/cloudevents/datacodec/xml/doc.go | 2 +- .../datacodec/xml/observability.go | 31 +++++--- .../sdk-go/pkg/cloudevents/event.go | 25 +++++++ .../sdk-go/pkg/cloudevents/event_response.go | 10 ++- .../sdk-go/pkg/cloudevents/eventcontext.go | 14 ++++ .../pkg/cloudevents/eventcontext_v01.go | 49 +++++++++++++ .../pkg/cloudevents/eventcontext_v02.go | 49 +++++++++++++ .../pkg/cloudevents/eventcontext_v03.go | 50 +++++++++++++ .../pkg/cloudevents/observability/keys.go | 6 +- .../pkg/cloudevents/observability/observer.go | 4 ++ .../pkg/cloudevents/transport/http/codec.go | 12 ++++ .../cloudevents/transport/http/codec_v01.go | 8 ++- .../cloudevents/transport/http/codec_v02.go | 8 ++- .../cloudevents/transport/http/codec_v03.go | 8 ++- .../pkg/cloudevents/transport/http/context.go | 9 +++ .../pkg/cloudevents/transport/http/doc.go | 2 +- .../cloudevents/transport/http/encoding.go | 13 ++++ .../pkg/cloudevents/transport/http/message.go | 4 ++ .../transport/http/observability.go | 60 ++++++++++------ .../pkg/cloudevents/transport/http/options.go | 1 + .../cloudevents/transport/http/transport.go | 72 ++++++++++++++----- .../pkg/cloudevents/transport/message.go | 6 +- .../pkg/cloudevents/transport/transport.go | 2 + .../sdk-go/pkg/cloudevents/types/allocate.go | 2 +- 40 files changed, 523 insertions(+), 147 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index 6df2a818d15..1b58aa67e7b 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -58,7 +58,7 @@ version = "v2.1.15" [[projects]] - digest = "1:7ded9717607b3eea18859dca3323fac420fa142ff4aa592cb07d8c7eb4a67d5e" + digest = "1:fd1744b6351c378ab9c77159c50626d626069e878ef616b31a59f2e40131b222" name = "github.com/cloudevents/sdk-go" packages = [ "pkg/cloudevents", @@ -74,8 +74,7 @@ "pkg/cloudevents/types", ] pruneopts = "NUT" - revision = "a4c06e590662f2aa30ac8f5974347c9832889765" - version = "0.4.1" + revision = "b88e53efaaadf77c676a5b53f64c2dc8814e1c6a" [[projects]] digest = "1:ffe9824d294da03b391f44e1ae8281281b4afc1bdaa9588c9097785e3af10cec" diff --git a/Gopkg.toml b/Gopkg.toml index 1007ae38aea..ed767bdd05c 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -131,7 +131,7 @@ required = [ name = "github.com/nats-io/nats-streaming-server" version = "0.11.0" -# The latest release as of March 20, 2019. [[constraint]] name = "github.com/cloudevents/sdk-go" - version = "=0.4.1" + # HEAD as of 2019-03-21 + revision = "b88e53efaaadf77c676a5b53f64c2dc8814e1c6a" diff --git a/pkg/apis/eventing/v1alpha1/eventtype_types.go b/pkg/apis/eventing/v1alpha1/eventtype_types.go index f742a06299c..01f15494107 100644 --- a/pkg/apis/eventing/v1alpha1/eventtype_types.go +++ b/pkg/apis/eventing/v1alpha1/eventtype_types.go @@ -65,6 +65,7 @@ type EventTypeSpec struct { // +optional Schema string `json:"schema,omitempty"` // TODO sink or broker? string or ref? + // TODO validate that the broker exists Broker string `json:"broker,omitempty"` } diff --git a/pkg/broker/ingress.go b/pkg/broker/ingress.go index ea1a9650ce0..85cad1e049c 100644 --- a/pkg/broker/ingress.go +++ b/pkg/broker/ingress.go @@ -135,11 +135,11 @@ func getEventType(c client.Client, event *cloudevents.Event, namespace string) ( return nil, err } for _, e := range el.Items { - // TODO update cloud events version once it is merged - // e.Spec.Origin == event.Extensions("Origin") && e.Spec.Schema == event.Extensions("Schema") - if e.Spec.Type == event.Type() { + // TODO what about source? + if e.Spec.Type == event.Type() && e.Spec.Schema == event.SchemaURL() { return &e, nil } + } if el.Continue != "" { opts.Raw.Continue = el.Continue @@ -162,8 +162,8 @@ func makeEventType(event *cloudevents.Event, namespace string) *eventingv1alpha1 }, Spec: eventingv1alpha1.EventTypeSpec{ Type: cloudEventType, - Source: "", // event.Source() - Schema: "", // event.SchemaURL() + Source: event.Source(), + Schema: event.SchemaURL(), // Waiting on https://github.com/knative/eventing/pull/937 Broker: "", }, diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/client/client.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/client/client.go index 41544d929b4..2a2ee3758a1 100644 --- a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/client/client.go +++ b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/client/client.go @@ -10,6 +10,7 @@ import ( "sync" ) +// Client interface defines the runtime contract the CloudEvents client supports. type Client interface { // Send will transmit the given event over the client's configured transport. Send(ctx context.Context, event cloudevents.Event) (*cloudevents.Event, error) @@ -36,6 +37,8 @@ type Client interface { StartReceiver(ctx context.Context, fn interface{}) error } +// New produces a new client with the provided transport object and applied +// client options. func New(t transport.Transport, opts ...Option) (Client, error) { c := &ceClient{ transport: t, @@ -48,7 +51,11 @@ func New(t transport.Transport, opts ...Option) (Client, error) { } // NewDefault provides the good defaults for the common case using an HTTP -// Transport client. +// Transport client. The http transport has had WithBinaryEncoding http +// transport option applied to it. The client will always send Binary +// encoding but will inspect the outbound event context and match the version. +// The WithtimeNow and WithUUIDs client options are also applied to the client, +// all outbound events will have a time and id set if not already present. func NewDefault() (Client, error) { t, err := http.New(http.WithBinaryEncoding()) if err != nil { @@ -69,8 +76,12 @@ type ceClient struct { eventDefaulterFns []EventDefaulter } +// Send transmits the provided event on a preconfigured Transport. +// Send returns a response event if there is a response or an error if there +// was an an issue validating the outbound event or the transport returns an +// error. func (c *ceClient) Send(ctx context.Context, event cloudevents.Event) (*cloudevents.Event, error) { - ctx, r := observability.NewReporter(ctx, ReportSend) + ctx, r := observability.NewReporter(ctx, reportSend) resp, err := c.obsSend(ctx, event) if err != nil { r.Error() @@ -101,7 +112,7 @@ func (c *ceClient) obsSend(ctx context.Context, event cloudevents.Event) (*cloud // Receive is called from from the transport on event delivery. func (c *ceClient) Receive(ctx context.Context, event cloudevents.Event, resp *cloudevents.EventResponse) error { - ctx, r := observability.NewReporter(ctx, ReportReceive) + ctx, r := observability.NewReporter(ctx, reportReceive) err := c.obsReceive(ctx, event, resp) if err != nil { r.Error() @@ -113,7 +124,7 @@ func (c *ceClient) Receive(ctx context.Context, event cloudevents.Event, resp *c func (c *ceClient) obsReceive(ctx context.Context, event cloudevents.Event, resp *cloudevents.EventResponse) error { if c.fn != nil { - ctx, rFn := observability.NewReporter(ctx, ReportReceiveFn) + ctx, rFn := observability.NewReporter(ctx, reportReceiveFn) err := c.fn.invoke(ctx, event, resp) if err != nil { rFn.Error() @@ -136,7 +147,8 @@ func (c *ceClient) obsReceive(ctx context.Context, event cloudevents.Event, resp return nil } -// Blocking Call +// StartReceiver sets up the given fn to handle Receive. +// See Client.StartReceiver for details. This is a blocking call. func (c *ceClient) StartReceiver(ctx context.Context, fn interface{}) error { c.receiverMu.Lock() defer c.receiverMu.Unlock() diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/client/defaulters.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/client/defaulters.go index ee87e0467a1..b1653264427 100644 --- a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/client/defaulters.go +++ b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/client/defaulters.go @@ -7,8 +7,12 @@ import ( "time" ) +// EventDefaulter is the function signature for extensions that are able +// to perform event defaulting. type EventDefaulter func(event cloudevents.Event) cloudevents.Event +// DefaultIDToUUIDIfNotSet will inspect the provided event and assign a UUID to +// context.ID if it is found to be empty. func DefaultIDToUUIDIfNotSet(event cloudevents.Event) cloudevents.Event { if event.Context != nil { switch event.Context.GetSpecVersion() { @@ -35,6 +39,8 @@ func DefaultIDToUUIDIfNotSet(event cloudevents.Event) cloudevents.Event { return event } +// DefaultTimeToNowIfNotSet will inspect the provided event and assign a new +// Timestamp to context.Time if it is found to be nil or zero. func DefaultTimeToNowIfNotSet(event cloudevents.Event) cloudevents.Event { if event.Context != nil { switch event.Context.GetSpecVersion() { diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/client/observability.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/client/observability.go index 69f0df2dfd6..b844c19a86e 100644 --- a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/client/observability.go +++ b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/client/observability.go @@ -7,10 +7,13 @@ import ( ) var ( - LatencyMs = stats.Float64("client/latency", "The latency in milliseconds for the CloudEvents client methods.", "ms") + // LatencyMs measures the latency in milliseconds for the CloudEvents + // client methods. + LatencyMs = stats.Float64("cloudevents.io/sdk-go/client/latency", "The latency in milliseconds for the CloudEvents client methods.", "ms") ) var ( + // LatencyView is an OpenCensus view that shows client method latency. LatencyView = &view.View{ Name: "client/latency", Measure: LatencyMs, @@ -20,40 +23,46 @@ var ( } ) -type Observed int32 +type observed int32 + +// Adheres to Observable +var _ observability.Observable = observed(0) const ( - ReportSend Observed = iota - ReportReceive - ReportReceiveFn + reportSend observed = iota + reportReceive + reportReceiveFn ) -func (o Observed) TraceName() string { +// TraceName implements Observable.TraceName +func (o observed) TraceName() string { switch o { - case ReportSend: + case reportSend: return "client/send" - case ReportReceive: + case reportReceive: return "client/receive" - case ReportReceiveFn: + case reportReceiveFn: return "client/receive/fn" default: return "client/unknown" } } -func (o Observed) MethodName() string { +// MethodName implements Observable.MethodName +func (o observed) MethodName() string { switch o { - case ReportSend: + case reportSend: return "send" - case ReportReceive: + case reportReceive: return "receive" - case ReportReceiveFn: + case reportReceiveFn: return "receive/fn" default: return "unknown" } } -func (o Observed) LatencyMs() *stats.Float64Measure { +// LatencyMs implements Observable.LatencyMs +func (o observed) LatencyMs() *stats.Float64Measure { return LatencyMs } diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/client/options.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/client/options.go index 09631d0835a..ec4ac7842f8 100644 --- a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/client/options.go +++ b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/client/options.go @@ -4,6 +4,7 @@ import ( "fmt" ) +// Option is the function signature required to be considered an client.Option. type Option func(*ceClient) error // WithEventDefaulter adds an event defaulter to the end of the defaulter chain. diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/codec/jsoncodec.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/codec/jsoncodec.go index 42847d88c0d..78d6765f890 100644 --- a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/codec/jsoncodec.go +++ b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/codec/jsoncodec.go @@ -13,7 +13,7 @@ import ( // JsonEncodeV01 takes in a cloudevent.Event and outputs the byte representation of that event using CloudEvents // version 0.1 structured json formatting rules. func JsonEncodeV01(e cloudevents.Event) ([]byte, error) { - _, r := observability.NewReporter(context.Background(), CodecObserved{o: ReportEncode, v: "v0.1"}) + _, r := observability.NewReporter(context.Background(), codecObserved{o: reportEncode, v: "v0.1"}) b, err := obsJsonEncodeV01(e) if err != nil { r.Error() @@ -34,7 +34,7 @@ func obsJsonEncodeV01(e cloudevents.Event) ([]byte, error) { // JsonEncodeV02 takes in a cloudevent.Event and outputs the byte representation of that event using CloudEvents // version 0.2 structured json formatting rules. func JsonEncodeV02(e cloudevents.Event) ([]byte, error) { - _, r := observability.NewReporter(context.Background(), CodecObserved{o: ReportEncode, v: "v0.2"}) + _, r := observability.NewReporter(context.Background(), codecObserved{o: reportEncode, v: "v0.2"}) b, err := obsJsonEncodeV02(e) if err != nil { r.Error() @@ -55,7 +55,7 @@ func obsJsonEncodeV02(e cloudevents.Event) ([]byte, error) { // JsonEncodeV03 takes in a cloudevent.Event and outputs the byte representation of that event using CloudEvents // version 0.3 structured json formatting rules. func JsonEncodeV03(e cloudevents.Event) ([]byte, error) { - _, r := observability.NewReporter(context.Background(), CodecObserved{o: ReportEncode, v: "v0.3"}) + _, r := observability.NewReporter(context.Background(), codecObserved{o: reportEncode, v: "v0.3"}) b, err := obsJsonEncodeV03(e) if err != nil { r.Error() @@ -113,7 +113,7 @@ func jsonEncode(ctx cloudevents.EventContext, data interface{}) ([]byte, error) // JsonDecodeV01 takes in the byte representation of a version 0.1 structured json CloudEvent and returns a // cloudevent.Event or an error if there are parsing errors. func JsonDecodeV01(body []byte) (*cloudevents.Event, error) { - _, r := observability.NewReporter(context.Background(), CodecObserved{o: ReportDecode, v: "v0.1"}) + _, r := observability.NewReporter(context.Background(), codecObserved{o: reportDecode, v: "v0.1"}) e, err := obsJsonDecodeV01(body) if err != nil { r.Error() @@ -148,7 +148,7 @@ func obsJsonDecodeV01(body []byte) (*cloudevents.Event, error) { // JsonDecodeV02 takes in the byte representation of a version 0.2 structured json CloudEvent and returns a // cloudevent.Event or an error if there are parsing errors. func JsonDecodeV02(body []byte) (*cloudevents.Event, error) { - _, r := observability.NewReporter(context.Background(), CodecObserved{o: ReportDecode, v: "v0.2"}) + _, r := observability.NewReporter(context.Background(), codecObserved{o: reportDecode, v: "v0.2"}) e, err := obsJsonDecodeV02(body) if err != nil { r.Error() @@ -183,7 +183,7 @@ func obsJsonDecodeV02(body []byte) (*cloudevents.Event, error) { // JsonDecodeV03 takes in the byte representation of a version 0.3 structured json CloudEvent and returns a // cloudevent.Event or an error if there are parsing errors. func JsonDecodeV03(body []byte) (*cloudevents.Event, error) { - _, r := observability.NewReporter(context.Background(), CodecObserved{o: ReportDecode, v: "v0.3"}) + _, r := observability.NewReporter(context.Background(), codecObserved{o: reportDecode, v: "v0.3"}) e, err := obsJsonDecodeV03(body) if err != nil { r.Error() diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/codec/observability.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/codec/observability.go index c710ea191f0..49bcb793d81 100644 --- a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/codec/observability.go +++ b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/codec/observability.go @@ -2,16 +2,19 @@ package codec import ( "fmt" + "github.com/cloudevents/sdk-go/pkg/cloudevents/observability" "go.opencensus.io/stats" "go.opencensus.io/stats/view" ) var ( - LatencyMs = stats.Float64("codec/json/latency", "The latency in milliseconds for the CloudEvents json codec methods.", "ms") + // LatencyMs measures the latency in milliseconds for the CloudEvents json codec methods. + LatencyMs = stats.Float64("cloudevents.io/sdk-go/codec/json/latency", "The latency in milliseconds for the CloudEvents json codec methods.", "ms") ) var ( + // LatencyView is an OpenCensus view that shows codec/json method latency. LatencyView = &view.View{ Name: "codec/json/latency", Measure: LatencyMs, @@ -21,55 +24,67 @@ var ( } ) -type Observed int32 +type observed int32 + +// Adheres to Observable +var _ observability.Observable = observed(0) const ( - ReportEncode Observed = iota - ReportDecode + reportEncode observed = iota + reportDecode ) -func (o Observed) TraceName() string { +// TraceName implements Observable.TraceName +func (o observed) TraceName() string { switch o { - case ReportEncode: + case reportEncode: return "codec/json/encode" - case ReportDecode: + case reportDecode: return "codec/json/decode" default: return "codec/unknown" } } -func (o Observed) MethodName() string { +// MethodName implements Observable.MethodName +func (o observed) MethodName() string { switch o { - case ReportEncode: + case reportEncode: return "encode" - case ReportDecode: + case reportDecode: return "decode" default: return "unknown" } } -func (o Observed) LatencyMs() *stats.Float64Measure { +// LatencyMs implements Observable.LatencyMs +func (o observed) LatencyMs() *stats.Float64Measure { return LatencyMs } -// CodecObserved is a wrapper to append version to Observed. -type CodecObserved struct { +// codecObserved is a wrapper to append version to observed. +type codecObserved struct { // Method - o Observed + o observed // Version v string } -func (c CodecObserved) TraceName() string { +// Adheres to Observable +var _ observability.Observable = (*codecObserved)(nil) + +// TraceName implements Observable.TraceName +func (c codecObserved) TraceName() string { return fmt.Sprintf("%s/%s", c.o.TraceName(), c.v) } -func (c CodecObserved) MethodName() string { +// MethodName implements Observable.MethodName +func (c codecObserved) MethodName() string { return fmt.Sprintf("%s/%s", c.o.MethodName(), c.v) } -func (c CodecObserved) LatencyMs() *stats.Float64Measure { +// LatencyMs implements Observable.LatencyMs +func (c codecObserved) LatencyMs() *stats.Float64Measure { return c.o.LatencyMs() } diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/datacodec/codec.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/datacodec/codec.go index 929a8754bb9..8deeb9d6674 100644 --- a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/datacodec/codec.go +++ b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/datacodec/codec.go @@ -50,7 +50,7 @@ func AddEncoder(contentType string, fn Encoder) { // content type. func Decode(contentType string, in, out interface{}) error { // TODO: wire in context. - _, r := observability.NewReporter(context.Background(), ReportDecode) + _, r := observability.NewReporter(context.Background(), reportDecode) err := obsDecode(contentType, in, out) if err != nil { r.Error() @@ -72,7 +72,7 @@ func obsDecode(contentType string, in, out interface{}) error { // content type. func Encode(contentType string, in interface{}) ([]byte, error) { // TODO: wire in context. - _, r := observability.NewReporter(context.Background(), ReportEncode) + _, r := observability.NewReporter(context.Background(), reportEncode) b, err := obsEncode(contentType, in) if err != nil { r.Error() diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/datacodec/json/data.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/datacodec/json/data.go index 9b362d305f2..ef2a69eb78c 100644 --- a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/datacodec/json/data.go +++ b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/datacodec/json/data.go @@ -14,7 +14,7 @@ import ( // to convert those bytes to `out`. Returns and error if this process fails. func Decode(in, out interface{}) error { // TODO: wire in context. - _, r := observability.NewReporter(context.Background(), ReportDecode) + _, r := observability.NewReporter(context.Background(), reportDecode) err := obsDecode(in, out) if err != nil { r.Error() @@ -64,7 +64,7 @@ func obsDecode(in, out interface{}) error { // Or json.Marshal errors. func Encode(in interface{}) ([]byte, error) { // TODO: wire in context. - _, r := observability.NewReporter(context.Background(), ReportEncode) + _, r := observability.NewReporter(context.Background(), reportEncode) b, err := obsEncode(in) if err != nil { r.Error() diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/datacodec/json/doc.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/datacodec/json/doc.go index 2f3d2982d25..86772c2e339 100644 --- a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/datacodec/json/doc.go +++ b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/datacodec/json/doc.go @@ -1,4 +1,4 @@ /* -Package datacodec/json holds the encoder/decoder implementation for `application/json`. +Package json holds the encoder/decoder implementation for `application/json`. */ package json diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/datacodec/json/observability.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/datacodec/json/observability.go index 5be43645486..d38a4b7d250 100644 --- a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/datacodec/json/observability.go +++ b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/datacodec/json/observability.go @@ -7,10 +7,13 @@ import ( ) var ( - LatencyMs = stats.Float64("datacodec/json/latency", "The latency in milliseconds for the CloudEvents json data codec methods.", "ms") + // LatencyMs measures the latency in milliseconds for the CloudEvents json + // data codec methods. + LatencyMs = stats.Float64("cloudevents.io/sdk-go/datacodec/json/latency", "The latency in milliseconds for the CloudEvents json data codec methods.", "ms") ) var ( + // LatencyView is an OpenCensus view that shows data codec json method latency. LatencyView = &view.View{ Name: "datacodec/json/latency", Measure: LatencyMs, @@ -20,35 +23,41 @@ var ( } ) -type Observed int32 +type observed int32 + +// Adheres to Observable +var _ observability.Observable = observed(0) const ( - ReportEncode Observed = iota - ReportDecode + reportEncode observed = iota + reportDecode ) -func (o Observed) TraceName() string { +// TraceName implements Observable.TraceName +func (o observed) TraceName() string { switch o { - case ReportEncode: + case reportEncode: return "datacodec/json/encode" - case ReportDecode: + case reportDecode: return "datacodec/json/decode" default: return "datacodec/json/unknown" } } -func (o Observed) MethodName() string { +// MethodName implements Observable.MethodName +func (o observed) MethodName() string { switch o { - case ReportEncode: + case reportEncode: return "encode" - case ReportDecode: + case reportDecode: return "decode" default: return "unknown" } } -func (o Observed) LatencyMs() *stats.Float64Measure { +// LatencyMs implements Observable.LatencyMs +func (o observed) LatencyMs() *stats.Float64Measure { return LatencyMs } diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/datacodec/observability.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/datacodec/observability.go index 0a87278f811..a51e05eb9fc 100644 --- a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/datacodec/observability.go +++ b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/datacodec/observability.go @@ -7,10 +7,13 @@ import ( ) var ( - LatencyMs = stats.Float64("datacodec/latency", "The latency in milliseconds for the CloudEvents generic data codec methods.", "ms") + // LatencyMs measures the latency in milliseconds for the CloudEvents generic + // codec data methods. + LatencyMs = stats.Float64("cloudevents.io/sdk-go/datacodec/latency", "The latency in milliseconds for the CloudEvents generic data codec methods.", "ms") ) var ( + // LatencyView is an OpenCensus view that shows data codec method latency. LatencyView = &view.View{ Name: "datacodec/latency", Measure: LatencyMs, @@ -20,35 +23,41 @@ var ( } ) -type Observed int32 +type observed int32 + +// Adheres to Observable +var _ observability.Observable = observed(0) const ( - ReportEncode Observed = iota - ReportDecode + reportEncode observed = iota + reportDecode ) -func (o Observed) TraceName() string { +// TraceName implements Observable.TraceName +func (o observed) TraceName() string { switch o { - case ReportEncode: + case reportEncode: return "datacodec/encode" - case ReportDecode: + case reportDecode: return "datacodec/decode" default: return "datacodec/unknown" } } -func (o Observed) MethodName() string { +// MethodName implements Observable.MethodName +func (o observed) MethodName() string { switch o { - case ReportEncode: + case reportEncode: return "encode" - case ReportDecode: + case reportDecode: return "decode" default: return "unknown" } } -func (o Observed) LatencyMs() *stats.Float64Measure { +// LatencyMs implements Observable.LatencyMs +func (o observed) LatencyMs() *stats.Float64Measure { return LatencyMs } diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/datacodec/xml/data.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/datacodec/xml/data.go index 8a644932f2a..047a961e0d2 100644 --- a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/datacodec/xml/data.go +++ b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/datacodec/xml/data.go @@ -14,7 +14,7 @@ import ( // to convert those bytes to `out`. Returns and error if this process fails. func Decode(in, out interface{}) error { // TODO: wire in context. - _, r := observability.NewReporter(context.Background(), ReportDecode) + _, r := observability.NewReporter(context.Background(), reportDecode) err := obsDecode(in, out) if err != nil { r.Error() @@ -69,7 +69,7 @@ func obsDecode(in, out interface{}) error { // Or xml.Marshal errors. func Encode(in interface{}) ([]byte, error) { // TODO: wire in context. - _, r := observability.NewReporter(context.Background(), ReportEncode) + _, r := observability.NewReporter(context.Background(), reportEncode) b, err := obsEncode(in) if err != nil { r.Error() diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/datacodec/xml/doc.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/datacodec/xml/doc.go index e7e013d3f02..d90b7c444da 100644 --- a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/datacodec/xml/doc.go +++ b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/datacodec/xml/doc.go @@ -1,4 +1,4 @@ /* -Package datacodec/xml holds the encoder/decoder implementation for `application/xml`. +Package xml holds the encoder/decoder implementation for `application/xml`. */ package xml diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/datacodec/xml/observability.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/datacodec/xml/observability.go index 4948c9be477..31b0bb26998 100644 --- a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/datacodec/xml/observability.go +++ b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/datacodec/xml/observability.go @@ -7,10 +7,13 @@ import ( ) var ( - LatencyMs = stats.Float64("datacodec/xml/latency", "The latency in milliseconds for the CloudEvents xml data codec methods.", "ms") + // LatencyMs measures the latency in milliseconds for the CloudEvents xml data + // codec methods. + LatencyMs = stats.Float64("cloudevents.io/sdk-go/datacodec/xml/latency", "The latency in milliseconds for the CloudEvents xml data codec methods.", "ms") ) var ( + // LatencyView is an OpenCensus view that shows data codec xml method latency. LatencyView = &view.View{ Name: "datacodec/xml/latency", Measure: LatencyMs, @@ -20,35 +23,41 @@ var ( } ) -type Observed int32 +type observed int32 + +// Adheres to Observable +var _ observability.Observable = observed(0) const ( - ReportEncode Observed = iota - ReportDecode + reportEncode observed = iota + reportDecode ) -func (o Observed) TraceName() string { +// TraceName implements Observable.TraceName +func (o observed) TraceName() string { switch o { - case ReportEncode: + case reportEncode: return "datacodec/xml/encode" - case ReportDecode: + case reportDecode: return "datacodec/xml/decode" default: return "datacodec/xml/unknown" } } -func (o Observed) MethodName() string { +// MethodName implements Observable.MethodName +func (o observed) MethodName() string { switch o { - case ReportEncode: + case reportEncode: return "encode" - case ReportDecode: + case reportDecode: return "decode" default: return "unknown" } } -func (o Observed) LatencyMs() *stats.Float64Measure { +// LatencyMs implements Observable.LatencyMs +func (o observed) LatencyMs() *stats.Float64Measure { return LatencyMs } diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/event.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/event.go index 4389a5de9b9..367c333b70d 100644 --- a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/event.go +++ b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/event.go @@ -15,22 +15,44 @@ type Event struct { Data interface{} } +// DataAs attempts to populate the provided data object with the event payload. +// data should be a pointer type. func (e Event) DataAs(data interface{}) error { return datacodec.Decode(e.Context.GetDataMediaType(), e.Data, data) } +// SpecVersion returns Context.GetSpecVersion() func (e Event) SpecVersion() string { return e.Context.GetSpecVersion() } +// Type returns Context.GetType() func (e Event) Type() string { return e.Context.GetType() } +// Source returns Context.GetSource() +func (e Event) Source() string { + return e.Context.GetSource() +} + +// SchemaURL returns Context.GetSchemaURL() +func (e Event) SchemaURL() string { + return e.Context.GetSchemaURL() +} + +// ExtensionAs returns Context.ExtensionAs(name, obj) +func (e Event) ExtensionAs(name string, obj interface{}) error { + return e.Context.ExtensionAs(name, obj) +} + +// DataContentType returns Context.getDataContentType() func (e Event) DataContentType() string { return e.Context.GetDataContentType() } +// Validate performs a spec based validation on this event. +// Validation is dependent on the spec version specified in the event context. func (e Event) Validate() error { if e.Context == nil { return fmt.Errorf("every event conforming to the CloudEvents specification MUST include a context") @@ -45,6 +67,7 @@ func (e Event) Validate() error { return nil } +// String returns a pretty-printed representation of the Event. func (e Event) String() string { b := strings.Builder{} @@ -64,6 +87,8 @@ func (e Event) String() string { var extensions map[string]interface{} + // TODO: This impl detail should be pushed into the impl structs. + switch e.SpecVersion() { case CloudEventsVersionV01: if ec, ok := e.Context.(EventContextV01); ok { diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/event_response.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/event_response.go index b8e09746204..0e5f7ce75d4 100644 --- a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/event_response.go +++ b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/event_response.go @@ -1,13 +1,19 @@ package cloudevents // EventResponse represents the canonical representation of a Response to a -// CloudEvent from a receiver. +// CloudEvent from a receiver. Response implementation is Transport dependent. type EventResponse struct { Status int Event *Event Reason string + // Context is transport specific struct to allow for controlling transport + // response details. + // For example, see http.TransportResponseContext. + Context interface{} } +// RespondWith sets up the instance of EventResponse to be set with status and +// an event. Response implementation is Transport dependent. func (e *EventResponse) RespondWith(status int, event *Event) { if e == nil { // if nil, response not supported @@ -19,6 +25,8 @@ func (e *EventResponse) RespondWith(status int, event *Event) { } } +// Error sets the instance of EventResponse to be set with an error code and +// reason string. Response implementation is Transport dependent. func (e *EventResponse) Error(status int, reason string) { if e == nil { // if nil, response not supported diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/eventcontext.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/eventcontext.go index 1f5b4d943c8..b437bf79c9a 100644 --- a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/eventcontext.go +++ b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/eventcontext.go @@ -1,5 +1,6 @@ package cloudevents +// EventContext is conical interface for a CloudEvents Context. type EventContext interface { // AsV01 provides a translation from whatever the "native" encoding of the // CloudEvent was to the equivalent in v0.1 field names, moving fields to or @@ -30,5 +31,18 @@ type EventContext interface { // GetType returns the CloudEvents type from the context. GetType() string + // GetSource returns the CloudEvents source from the context. + GetSource() string + + // GetSchemaURL returns the CloudEvents schema URL (if any) from the context. + GetSchemaURL() string + + // ExtensionAs populates 'obj' with the CloudEvents extension 'name' from the context. + // It returns an error if the extension 'name' does not exist, the extension's type + // does not match the 'obj' type, or if the 'obj' type is not a supported. + ExtensionAs(name string, obj interface{}) error + + // Validate the event based on the specifics of the CloudEvents spec version + // represented by this event context. Validate() error } diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/eventcontext_v01.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/eventcontext_v01.go index 318df337ac2..e4293cfb1b0 100644 --- a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/eventcontext_v01.go +++ b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/eventcontext_v01.go @@ -38,8 +38,10 @@ type EventContextV01 struct { Extensions map[string]interface{} `json:"extensions,omitempty"` } +// Adhere to EventContext var _ EventContext = (*EventContextV01)(nil) +// GetSpecVersion implements EventContext.GetSpecVersion func (ec EventContextV01) GetSpecVersion() string { if ec.CloudEventsVersion != "" { return ec.CloudEventsVersion @@ -47,6 +49,7 @@ func (ec EventContextV01) GetSpecVersion() string { return CloudEventsVersionV01 } +// GetDataContentType implements EventContext.GetDataContentType func (ec EventContextV01) GetDataContentType() string { if ec.ContentType != nil { return *ec.ContentType @@ -54,6 +57,7 @@ func (ec EventContextV01) GetDataContentType() string { return "" } +// GetDataMediaType implements EventContext.GetDataMediaType func (ec EventContextV01) GetDataMediaType() string { if ec.ContentType != nil { mediaType, _, err := mime.ParseMediaType(*ec.ContentType) @@ -66,15 +70,59 @@ func (ec EventContextV01) GetDataMediaType() string { return "" } +// GetType implements EventContext.GetType func (ec EventContextV01) GetType() string { return ec.EventType } +// GetSource implements EventContext.GetSource +func (ec EventContextV01) GetSource() string { + return ec.Source.String() +} + +// GetSchemaURL implements EventContext.GetSchemaURL +func (ec EventContextV01) GetSchemaURL() string { + if ec.SchemaURL != nil { + return ec.SchemaURL.String() + } + return "" +} + +// ExtensionAs implements EventContext.ExtensionAs +func (ec EventContextV01) ExtensionAs(name string, obj interface{}) error { + value, ok := ec.Extensions[name] + if !ok { + return fmt.Errorf("extension %q does not exist", name) + } + // Only support *string for now. + switch v := obj.(type) { + case *string: + if valueAsString, ok := value.(string); ok { + *v = valueAsString + return nil + } else { + return fmt.Errorf("invalid type for extension %q", name) + } + default: + return fmt.Errorf("unkown extension type %T", obj) + } +} + +// SetExtension adds the extension 'name' with value 'value' to the CloudEvents context. +func (ec *EventContextV01) SetExtension(name string, value interface{}) { + if ec.Extensions == nil { + ec.Extensions = make(map[string]interface{}) + } + ec.Extensions[name] = value +} + +// AsV01 implements EventContext.AsV01 func (ec EventContextV01) AsV01() EventContextV01 { ec.CloudEventsVersion = CloudEventsVersionV01 return ec } +// AsV02 implements EventContext.AsV02 func (ec EventContextV01) AsV02() EventContextV02 { ret := EventContextV02{ SpecVersion: CloudEventsVersionV02, @@ -102,6 +150,7 @@ func (ec EventContextV01) AsV02() EventContextV02 { return ret } +// AsV03 implements EventContext.AsV03 func (ec EventContextV01) AsV03() EventContextV03 { ecv2 := ec.AsV02() return ecv2.AsV03() diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/eventcontext_v02.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/eventcontext_v02.go index c2bdba2d246..0aa961813f2 100644 --- a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/eventcontext_v02.go +++ b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/eventcontext_v02.go @@ -35,8 +35,10 @@ type EventContextV02 struct { Extensions map[string]interface{} `json:"-,omitempty"` // TODO: decide how we want extensions to be inserted } +// Adhere to EventContext var _ EventContext = (*EventContextV02)(nil) +// GetSpecVersion implements EventContext.GetSpecVersion func (ec EventContextV02) GetSpecVersion() string { if ec.SpecVersion != "" { return ec.SpecVersion @@ -44,6 +46,7 @@ func (ec EventContextV02) GetSpecVersion() string { return CloudEventsVersionV02 } +// GetDataContentType implements EventContext.GetDataContentType func (ec EventContextV02) GetDataContentType() string { if ec.ContentType != nil { return *ec.ContentType @@ -51,6 +54,7 @@ func (ec EventContextV02) GetDataContentType() string { return "" } +// GetDataMediaType implements EventContext.GetDataMediaType func (ec EventContextV02) GetDataMediaType() string { if ec.ContentType != nil { mediaType, _, err := mime.ParseMediaType(*ec.ContentType) @@ -63,10 +67,53 @@ func (ec EventContextV02) GetDataMediaType() string { return "" } +// GetType implements EventContext.GetType func (ec EventContextV02) GetType() string { return ec.Type } +// GetSource implements EventContext.GetSource +func (ec EventContextV02) GetSource() string { + return ec.Source.String() +} + +// GetSchemaURL implements EventContext.GetSchemaURL +func (ec EventContextV02) GetSchemaURL() string { + if ec.SchemaURL != nil { + return ec.SchemaURL.String() + } + return "" +} + +// ExtensionAs implements EventContext.ExtensionAs +func (ec EventContextV02) ExtensionAs(name string, obj interface{}) error { + value, ok := ec.Extensions[name] + if !ok { + return fmt.Errorf("extension %q does not exist", name) + } + // Only support *string for now. + switch v := obj.(type) { + case *string: + if valueAsString, ok := value.(string); ok { + *v = valueAsString + return nil + } else { + return fmt.Errorf("invalid type for extension %q", name) + } + default: + return fmt.Errorf("unkown extension type %T", obj) + } +} + +// SetExtension adds the extension 'name' with value 'value' to the CloudEvents context. +func (ec *EventContextV02) SetExtension(name string, value interface{}) { + if ec.Extensions == nil { + ec.Extensions = make(map[string]interface{}) + } + ec.Extensions[name] = value +} + +// AsV01 implements EventContext.AsV01 func (ec EventContextV02) AsV01() EventContextV01 { ret := EventContextV01{ CloudEventsVersion: CloudEventsVersionV01, @@ -96,11 +143,13 @@ func (ec EventContextV02) AsV01() EventContextV01 { return ret } +// AsV02 implements EventContext.AsV02 func (ec EventContextV02) AsV02() EventContextV02 { ec.SpecVersion = CloudEventsVersionV02 return ec } +// AsV03 implements EventContext.AsV03 func (ec EventContextV02) AsV03() EventContextV03 { ret := EventContextV03{ SpecVersion: CloudEventsVersionV03, diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/eventcontext_v03.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/eventcontext_v03.go index 465a815d1c9..cbb923d1dcd 100644 --- a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/eventcontext_v03.go +++ b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/eventcontext_v03.go @@ -37,8 +37,10 @@ type EventContextV03 struct { Extensions map[string]interface{} `json:"-,omitempty"` // TODO: decide how we want extensions to be inserted } +// Adhere to EventContext var _ EventContext = (*EventContextV03)(nil) +// GetSpecVersion implements EventContext.GetSpecVersion func (ec EventContextV03) GetSpecVersion() string { if ec.SpecVersion != "" { return ec.SpecVersion @@ -46,6 +48,7 @@ func (ec EventContextV03) GetSpecVersion() string { return CloudEventsVersionV03 } +// GetDataContentType implements EventContext.GetDataContentType func (ec EventContextV03) GetDataContentType() string { if ec.DataContentType != nil { return *ec.DataContentType @@ -53,6 +56,7 @@ func (ec EventContextV03) GetDataContentType() string { return "" } +// GetDataMediaType implements EventContext.GetDataMediaType func (ec EventContextV03) GetDataMediaType() string { if ec.DataContentType != nil { mediaType, _, err := mime.ParseMediaType(*ec.DataContentType) @@ -64,15 +68,60 @@ func (ec EventContextV03) GetDataMediaType() string { } return "" } + +// GetType implements EventContext.GetType func (ec EventContextV03) GetType() string { return ec.Type } +// GetSource implements EventContext.GetSource +func (ec EventContextV03) GetSource() string { + return ec.Source.String() +} + +// GetSchemaURL implements EventContext.GetSchemaURL +func (ec EventContextV03) GetSchemaURL() string { + if ec.SchemaURL != nil { + return ec.SchemaURL.String() + } + return "" +} + +// ExtensionAs implements EventContext.ExtensionAs +func (ec EventContextV03) ExtensionAs(name string, obj interface{}) error { + value, ok := ec.Extensions[name] + if !ok { + return fmt.Errorf("extension %q does not exist", name) + } + // Only support *string for now. + switch v := obj.(type) { + case *string: + if valueAsString, ok := value.(string); ok { + *v = valueAsString + return nil + } else { + return fmt.Errorf("invalid type for extension %q", name) + } + default: + return fmt.Errorf("unkown extension type %T", obj) + } +} + +// SetExtension adds the extension 'name' with value 'value' to the CloudEvents context. +func (ec *EventContextV03) SetExtension(name string, value interface{}) { + if ec.Extensions == nil { + ec.Extensions = make(map[string]interface{}) + } + ec.Extensions[name] = value +} + +// AsV01 implements EventContext.AsV01 func (ec EventContextV03) AsV01() EventContextV01 { ecv2 := ec.AsV02() return ecv2.AsV01() } +// AsV02 implements EventContext.AsV02 func (ec EventContextV03) AsV02() EventContextV02 { ret := EventContextV02{ SpecVersion: CloudEventsVersionV02, @@ -87,6 +136,7 @@ func (ec EventContextV03) AsV02() EventContextV02 { return ret } +// AsV03 implements EventContext.AsV03 func (ec EventContextV03) AsV03() EventContextV03 { ec.SpecVersion = CloudEventsVersionV03 return ec diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/observability/keys.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/observability/keys.go index d9f961e86c7..f032b10ecf7 100644 --- a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/observability/keys.go +++ b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/observability/keys.go @@ -5,11 +5,15 @@ import ( ) var ( + // KeyMethod is the tag used for marking method on a metric. KeyMethod, _ = tag.NewKey("method") + // KeyResult is the tag used for marking result on a metric. KeyResult, _ = tag.NewKey("result") ) const ( + // ResultError is a shared result tag value for error. ResultError = "error" - ResultOK = "success" + // ResultOK is a shared result tag value for success. + ResultOK = "success" ) diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/observability/observer.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/observability/observer.go index 944059b5c37..a7936f4b987 100644 --- a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/observability/observer.go +++ b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/observability/observer.go @@ -40,6 +40,8 @@ func LatencyTags() []tag.Key { return []tag.Key{KeyMethod, KeyResult} } +// NewReporter creates and returns a reporter wrapping the provided Observable, +// and injects a trace span into the context. func NewReporter(ctx context.Context, on Observable) (context.Context, Reporter) { ctx, span := trace.StartSpan(ctx, on.TraceName()) r := &reporter{ @@ -66,12 +68,14 @@ func (r *reporter) record() { r.span.End() } +// Error records the result as an error. func (r *reporter) Error() { r.once.Do(func() { r.result(ResultError) }) } +// OK records the result as a success. func (r *reporter) OK() { r.once.Do(func() { r.result(ResultOK) diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http/codec.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http/codec.go index 5493a1ecb35..f6faf3c49f1 100644 --- a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http/codec.go +++ b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http/codec.go @@ -7,9 +7,14 @@ import ( "github.com/cloudevents/sdk-go/pkg/cloudevents/transport" ) +// Codec is the wrapper for all versions of codecs supported by the http +// transport. type Codec struct { + // Encoding is the setting to inform the DefaultEncodingSelectionFn for + // selecting a codec. Encoding Encoding + // DefaultEncodingSelectionFn allows for encoding selection strategies to be injected. DefaultEncodingSelectionFn EncodingSelector v01 *CodecV01 @@ -17,8 +22,11 @@ type Codec struct { v03 *CodecV03 } +// Adheres to Codec var _ transport.Codec = (*Codec)(nil) +// DefaultBinaryEncodingSelectionStrategy implements a selection process for +// which binary encoding to use based on spec version of the event. func DefaultBinaryEncodingSelectionStrategy(e cloudevents.Event) Encoding { switch e.SpecVersion() { case cloudevents.CloudEventsVersionV01: @@ -32,6 +40,8 @@ func DefaultBinaryEncodingSelectionStrategy(e cloudevents.Event) Encoding { return Default } +// DefaultStructuredEncodingSelectionStrategy implements a selection process +// for which structured encoding to use based on spec version of the event. func DefaultStructuredEncodingSelectionStrategy(e cloudevents.Event) Encoding { switch e.SpecVersion() { case cloudevents.CloudEventsVersionV01: @@ -45,6 +55,7 @@ func DefaultStructuredEncodingSelectionStrategy(e cloudevents.Event) Encoding { return Default } +// Encode encodes the provided event into a transport message. func (c *Codec) Encode(e cloudevents.Event) (transport.Message, error) { encoding := c.Encoding @@ -81,6 +92,7 @@ func (c *Codec) Encode(e cloudevents.Event) (transport.Message, error) { } } +// Decode converts a provided transport message into an Event, or error. func (c *Codec) Decode(msg transport.Message) (*cloudevents.Event, error) { switch c.inspectEncoding(msg) { case BinaryV01: diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http/codec_v01.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http/codec_v01.go index 7a23d707d6e..d8171370c2c 100644 --- a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http/codec_v01.go +++ b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http/codec_v01.go @@ -15,15 +15,18 @@ import ( "strings" ) +// CodecV01 represents a http transport codec that uses CloudEvents spec v0.3 type CodecV01 struct { Encoding Encoding } +// Adheres to Codec var _ transport.Codec = (*CodecV01)(nil) +// Encode implements Codec.Encode func (v CodecV01) Encode(e cloudevents.Event) (transport.Message, error) { // TODO: wire context - _, r := observability.NewReporter(context.Background(), CodecObserved{o: ReportEncode, c: v.Encoding.Codec()}) + _, r := observability.NewReporter(context.Background(), CodecObserved{o: reportEncode, c: v.Encoding.Codec()}) m, err := v.obsEncode(e) if err != nil { r.Error() @@ -46,9 +49,10 @@ func (v CodecV01) obsEncode(e cloudevents.Event) (transport.Message, error) { } } +// Decode implements Codec.Decode func (v CodecV01) Decode(msg transport.Message) (*cloudevents.Event, error) { // TODO: wire context - _, r := observability.NewReporter(context.Background(), CodecObserved{o: ReportDecode, c: v.inspectEncoding(msg).Codec()}) // TODO: inspectEncoding is not free. + _, r := observability.NewReporter(context.Background(), CodecObserved{o: reportDecode, c: v.inspectEncoding(msg).Codec()}) // TODO: inspectEncoding is not free. e, err := v.obsDecode(msg) if err != nil { r.Error() diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http/codec_v02.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http/codec_v02.go index 5377a973494..3c04b9aabc1 100644 --- a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http/codec_v02.go +++ b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http/codec_v02.go @@ -15,15 +15,18 @@ import ( "strings" ) +// CodecV02 represents a http transport codec that uses CloudEvents spec v0.2 type CodecV02 struct { Encoding Encoding } +// Adheres to Codec var _ transport.Codec = (*CodecV02)(nil) +// Encode implements Codec.Encode func (v CodecV02) Encode(e cloudevents.Event) (transport.Message, error) { // TODO: wire context - _, r := observability.NewReporter(context.Background(), CodecObserved{o: ReportEncode, c: v.Encoding.Codec()}) + _, r := observability.NewReporter(context.Background(), CodecObserved{o: reportEncode, c: v.Encoding.Codec()}) m, err := v.obsEncode(e) if err != nil { r.Error() @@ -46,9 +49,10 @@ func (v CodecV02) obsEncode(e cloudevents.Event) (transport.Message, error) { } } +// Decode implements Codec.Decode func (v CodecV02) Decode(msg transport.Message) (*cloudevents.Event, error) { // TODO: wire context - _, r := observability.NewReporter(context.Background(), CodecObserved{o: ReportDecode, c: v.inspectEncoding(msg).Codec()}) // TODO: inspectEncoding is not free. + _, r := observability.NewReporter(context.Background(), CodecObserved{o: reportDecode, c: v.inspectEncoding(msg).Codec()}) // TODO: inspectEncoding is not free. e, err := v.obsDecode(msg) if err != nil { r.Error() diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http/codec_v03.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http/codec_v03.go index 0ceee6aa90f..f2964ed1bb1 100644 --- a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http/codec_v03.go +++ b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http/codec_v03.go @@ -15,15 +15,18 @@ import ( "strings" ) +// CodecV03 represents a http transport codec that uses CloudEvents spec v0.3 type CodecV03 struct { Encoding Encoding } +// Adheres to Codec var _ transport.Codec = (*CodecV03)(nil) +// Encode implements Codec.Encode func (v CodecV03) Encode(e cloudevents.Event) (transport.Message, error) { // TODO: wire context - _, r := observability.NewReporter(context.Background(), CodecObserved{o: ReportEncode, c: v.Encoding.Codec()}) + _, r := observability.NewReporter(context.Background(), CodecObserved{o: reportEncode, c: v.Encoding.Codec()}) m, err := v.obsEncode(e) if err != nil { r.Error() @@ -48,9 +51,10 @@ func (v CodecV03) obsEncode(e cloudevents.Event) (transport.Message, error) { } } +// Decode implements Codec.Decode func (v CodecV03) Decode(msg transport.Message) (*cloudevents.Event, error) { // TODO: wire context - _, r := observability.NewReporter(context.Background(), CodecObserved{o: ReportDecode, c: v.inspectEncoding(msg).Codec()}) // TODO: inspectEncoding is not free. + _, r := observability.NewReporter(context.Background(), CodecObserved{o: reportDecode, c: v.inspectEncoding(msg).Codec()}) // TODO: inspectEncoding is not free. e, err := v.obsDecode(msg) if err != nil { r.Error() diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http/context.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http/context.go index b0a397e210e..e809c3a31c8 100644 --- a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http/context.go +++ b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http/context.go @@ -19,6 +19,7 @@ type TransportContext struct { IgnoreHeaderPrefixes []string } +// NewTransportContext creates a new TransportContext from a http.Request. func NewTransportContext(req *http.Request) TransportContext { var tx *TransportContext if req != nil { @@ -35,6 +36,12 @@ func NewTransportContext(req *http.Request) TransportContext { return *tx } +// TransportResponseContext allows a Receiver response with http transport specific fields. +type TransportResponseContext struct { + // Header will be merged with the response headers. + Header http.Header +} + // AttendToHeaders returns the list of headers that exist in the TransportContext that are not currently in // tx.IgnoreHeaderPrefix. func (tx TransportContext) AttendToHeaders() []string { @@ -110,6 +117,8 @@ func WithTransportContext(ctx context.Context, tcxt TransportContext) context.Co return context.WithValue(ctx, transportContextKey, tcxt) } +// TransportContextFrom pulls a TransportContext out of a context. Always +// returns a non-nil object. func TransportContextFrom(ctx context.Context) TransportContext { tctx := ctx.Value(transportContextKey) if tctx != nil { diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http/doc.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http/doc.go index 7a8df0e88a2..1a171e46e1e 100644 --- a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http/doc.go +++ b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http/doc.go @@ -1,4 +1,4 @@ /* -Package transport/http implements the CloudEvent transport implementation using HTTP. +Package http implements the CloudEvent transport implementation using HTTP. */ package http diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http/encoding.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http/encoding.go index 92017cbf372..ca62e5b5df9 100644 --- a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http/encoding.go +++ b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http/encoding.go @@ -1,19 +1,30 @@ package http +// Encoding to use for HTTP transport. type Encoding int32 const ( + // Default Default Encoding = iota + // BinaryV01 is Binary CloudEvents spec v0.1. BinaryV01 + // StructuredV01 is Structured CloudEvents spec v0.1. StructuredV01 + // BinaryV02 is Binary CloudEvents spec v0.2. BinaryV02 + // StructuredV02 is Structured CloudEvents spec v0.2. StructuredV02 + // BinaryV03 is Binary CloudEvents spec v0.3. BinaryV03 + // StructuredV03 is Structured CloudEvents spec v0.3. StructuredV03 + // BatchedV03 is Batched CloudEvents spec v0.3. BatchedV03 + // Unknown is unknown. Unknown ) +// String pretty-prints the encoding as a string. func (e Encoding) String() string { switch e { case Default: @@ -44,6 +55,7 @@ func (e Encoding) String() string { } } +// Version pretty-prints the encoding version as a string. func (e Encoding) Version() string { switch e { case Default: @@ -75,6 +87,7 @@ func (e Encoding) Version() string { } } +// Codec creates a structured string to represent the the codec version. func (e Encoding) Codec() string { switch e { case Default: diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http/message.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http/message.go index f9c55265039..0c5748c0b94 100644 --- a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http/message.go +++ b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http/message.go @@ -9,17 +9,21 @@ import ( // type check that this transport message impl matches the contract var _ transport.Message = (*Message)(nil) +// Message is an http transport message. type Message struct { Header http.Header Body []byte } +// Response is an http transport response. type Response struct { StatusCode int Header http.Header Body []byte } +// CloudEventsVersion inspects a message and tries to discover and return the +// CloudEvents spec version. func (m Message) CloudEventsVersion() string { // TODO: the impl of this method needs to move into the codec. diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http/observability.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http/observability.go index b87ca8dd998..1da56dc2ad5 100644 --- a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http/observability.go +++ b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http/observability.go @@ -2,19 +2,23 @@ package http import ( "fmt" + "github.com/cloudevents/sdk-go/pkg/cloudevents/observability" "go.opencensus.io/stats" "go.opencensus.io/stats/view" ) var ( + // LatencyMs measures the latency in milliseconds for the http transport + // methods for CloudEvents. LatencyMs = stats.Float64( - "transport/http/latency", + "cloudevents.io/sdk-go/transport/http/latency", "The latency in milliseconds for the http transport methods for CloudEvents.", "ms") ) var ( + // LatencyView is an OpenCensus view that shows http transport method latency. LatencyView = &view.View{ Name: "transport/http/latency", Measure: LatencyMs, @@ -24,70 +28,82 @@ var ( } ) -type Observed int32 +type observed int32 + +// Adheres to Observable +var _ observability.Observable = observed(0) const ( - ReportSend Observed = iota - ReportReceive - ReportServeHTTP - ReportEncode - ReportDecode + reportSend observed = iota + reportReceive + reportServeHTTP + reportEncode + reportDecode ) -func (o Observed) TraceName() string { +// TraceName implements Observable.TraceName +func (o observed) TraceName() string { switch o { - case ReportSend: + case reportSend: return "transport/http/send" - case ReportReceive: + case reportReceive: return "transport/http/receive" - case ReportServeHTTP: + case reportServeHTTP: return "transport/http/servehttp" - case ReportEncode: + case reportEncode: return "transport/http/encode" - case ReportDecode: + case reportDecode: return "transport/http/decode" default: return "transport/http/unknown" } } -func (o Observed) MethodName() string { +// MethodName implements Observable.MethodName +func (o observed) MethodName() string { switch o { - case ReportSend: + case reportSend: return "send" - case ReportReceive: + case reportReceive: return "receive" - case ReportServeHTTP: + case reportServeHTTP: return "servehttp" - case ReportEncode: + case reportEncode: return "encode" - case ReportDecode: + case reportDecode: return "decode" default: return "unknown" } } -func (o Observed) LatencyMs() *stats.Float64Measure { +// LatencyMs implements Observable.LatencyMs +func (o observed) LatencyMs() *stats.Float64Measure { return LatencyMs } -// CodecObserved is a wrapper to append version to Observed. +// CodecObserved is a wrapper to append version to observed. type CodecObserved struct { // Method - o Observed + o observed // Codec c string } +// Adheres to Observable +var _ observability.Observable = (*CodecObserved)(nil) + +// TraceName implements Observable.TraceName func (c CodecObserved) TraceName() string { return fmt.Sprintf("%s/%s", c.o.TraceName(), c.c) } +// MethodName implements Observable.MethodName func (c CodecObserved) MethodName() string { return fmt.Sprintf("%s/%s", c.o.MethodName(), c.c) } +// LatencyMs implements Observable.LatencyMs func (c CodecObserved) LatencyMs() *stats.Float64Measure { return c.o.LatencyMs() } diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http/options.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http/options.go index 0f8e70901b2..226bb92553f 100644 --- a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http/options.go +++ b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http/options.go @@ -8,6 +8,7 @@ import ( "time" ) +// Option is the function signature required to be considered an http.Option. type Option func(*Transport) error // WithTarget sets the outbound recipient of cloudevents when using an HTTP diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http/transport.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http/transport.go index 90b1c2ec8ef..39761c90dd6 100644 --- a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http/transport.go +++ b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http/transport.go @@ -20,7 +20,7 @@ import ( type EncodingSelector func(e cloudevents.Event) Encoding -// type check that this transport message impl matches the contract +// Transport adheres to transport.Transport. var _ transport.Transport = (*Transport)(nil) const ( @@ -30,7 +30,9 @@ const ( // Transport acts as both a http client and a http handler. type Transport struct { - Encoding Encoding + // The encoding used to select the codec for outbound events. + Encoding Encoding + // DefaultEncodingSelectionFn allows for other encoding selection strategies to be injected. DefaultEncodingSelectionFn EncodingSelector // ShutdownTimeout defines the timeout given to the http.Server when calling Shutdown. @@ -38,14 +40,27 @@ type Transport struct { ShutdownTimeout *time.Duration // Sending + + // Client is the http client that will be used to send requests. + // If nil, the Transport will create a one. Client *http.Client - Req *http.Request + // Req is the base http request that is used for http.Do. + // Only .Method, .URL, and .Header is considered. + // If not set, Req.Method defaults to POST. + // Req.URL or context.WithTarget(url) are required for sending. + Req *http.Request // Receiving + + // Receiver is invoked target for incoming events. Receiver transport.Receiver - Port *int // if nil, default 8080 - Path string // if "", default "/" - Handler *http.ServeMux + // Port is the port to bind the receiver to. Defaults to 8080. + Port *int + // Path is the path to bind the receiver to. Defaults to "/". + Path string + // Handler is the handler the http Server will use. Use this to reuse the + // http server. If nil, the Transport will create a one. + Handler *http.ServeMux realPort int server *http.Server @@ -104,8 +119,9 @@ func copyHeaders(from, to http.Header) { } } +// Send implements Transport.Send func (t *Transport) Send(ctx context.Context, event cloudevents.Event) (*cloudevents.Event, error) { - ctx, r := observability.NewReporter(ctx, ReportSend) + ctx, r := observability.NewReporter(ctx, reportSend) resp, err := t.obsSend(ctx, event) if err != nil { r.Error() @@ -150,7 +166,7 @@ func (t *Transport) obsSend(ctx context.Context, event cloudevents.Event) (*clou req.Body = ioutil.NopCloser(bytes.NewBuffer(m.Body)) req.ContentLength = int64(len(m.Body)) req.Close = true - return httpDo(ctx, &req, func(resp *http.Response, err error) (*cloudevents.Event, error) { + return httpDo(ctx, t.Client, &req, func(resp *http.Response, err error) (*cloudevents.Event, error) { if err != nil { return nil, err } @@ -182,10 +198,13 @@ func (t *Transport) obsSend(ctx context.Context, event cloudevents.Event) (*clou return nil, fmt.Errorf("failed to encode Event into a Message") } +// SetReceiver implements Transport.SetReceiver func (t *Transport) SetReceiver(r transport.Receiver) { t.Receiver = r } +// StartReceiver implements Transport.StartReceiver +// NOTE: This is a blocking call. func (t *Transport) StartReceiver(ctx context.Context) error { t.reMu.Lock() defer t.reMu.Unlock() @@ -244,12 +263,12 @@ type eventError struct { err error } -func httpDo(ctx context.Context, req *http.Request, fn func(*http.Response, error) (*cloudevents.Event, error)) (*cloudevents.Event, error) { +func httpDo(ctx context.Context, client *http.Client, req *http.Request, fn func(*http.Response, error) (*cloudevents.Event, error)) (*cloudevents.Event, error) { // Run the HTTP request in a goroutine and pass the response to fn. c := make(chan eventError, 1) req = req.WithContext(ctx) go func() { - event, err := fn(http.DefaultClient.Do(req)) + event, err := fn(client.Do(req)) c <- eventError{event: event, err: err} }() select { @@ -280,7 +299,7 @@ func status(resp *http.Response) string { } func (t *Transport) invokeReceiver(ctx context.Context, event cloudevents.Event) (*Response, error) { - ctx, r := observability.NewReporter(ctx, ReportReceive) + ctx, r := observability.NewReporter(ctx, reportReceive) resp, err := t.obsInvokeReceiver(ctx, event) if err != nil { r.Error() @@ -316,6 +335,19 @@ func (t *Transport) obsInvokeReceiver(ctx context.Context, event cloudevents.Eve resp.StatusCode = http.StatusInternalServerError return &resp, err } + // Look for a transport response context + var trx *TransportResponseContext + if ptrTrx, ok := eventResp.Context.(*TransportResponseContext); ok { + // found a *TransportResponseContext, use it. + trx = ptrTrx + } else if realTrx, ok := eventResp.Context.(TransportResponseContext); ok { + // found a TransportResponseContext, make it a pointer. + trx = &realTrx + } + // If we found a TransportResponseContext, use it. + if trx != nil && trx.Header != nil && len(trx.Header) > 0 { + copyHeaders(trx.Header, resp.Header) + } } if eventResp.Status != 0 { @@ -330,7 +362,7 @@ func (t *Transport) obsInvokeReceiver(ctx context.Context, event cloudevents.Eve // ServeHTTP implements http.Handler func (t *Transport) ServeHTTP(w http.ResponseWriter, req *http.Request) { - ctx, r := observability.NewReporter(req.Context(), ReportServeHTTP) + ctx, r := observability.NewReporter(req.Context(), reportServeHTTP) body, err := ioutil.ReadAll(req.Body) if err != nil { @@ -374,12 +406,11 @@ func (t *Transport) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } if resp != nil { + if t.Req != nil { + copyHeaders(t.Req.Header, w.Header()) + } if len(resp.Header) > 0 { - for k, vs := range resp.Header { - for _, v := range vs { - w.Header().Set(k, v) - } - } + copyHeaders(resp.Header, w.Header()) } status := http.StatusAccepted if resp.StatusCode >= 200 && resp.StatusCode < 600 { @@ -401,6 +432,9 @@ func (t *Transport) ServeHTTP(w http.ResponseWriter, req *http.Request) { r.OK() } +// GetPort returns the port the transport is active on. +// .Port can be set to 0, which means the transport selects a port, GetPort +// allows the transport to report back the selected port. func (t *Transport) GetPort() int { if t.Port != nil && *t.Port == 0 && t.realPort != 0 { return t.realPort @@ -412,6 +446,10 @@ func (t *Transport) GetPort() int { return 8080 // default } +// GetPath returns the path the transport is hosted on. If the path is '/', +// the transport will handle requests on any URI. To discover the true path +// a request was received on, inspect the context from Receive(cxt, ...) with +// TransportContextFrom(ctx). func (t *Transport) GetPath() string { path := strings.TrimSpace(t.Path) if len(path) > 0 { diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/message.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/message.go index bef74aa663c..e2ed55c970f 100644 --- a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/message.go +++ b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/message.go @@ -1,13 +1,9 @@ package transport +// Message is the abstract transport message wrapper. type Message interface { // CloudEventsVersion returns the version of the CloudEvent. CloudEventsVersion() string // TODO maybe get encoding } - -type Response struct { - ResponseCode int - Body []byte -} diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/transport.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/transport.go index 313e4d07b20..75c652b9233 100644 --- a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/transport.go +++ b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/transport.go @@ -14,6 +14,8 @@ type Transport interface { StartReceiver(context.Context) error } +// Receiver is an interface to define how a transport will invoke a listener +// of incoming events. type Receiver interface { Receive(context.Context, cloudevents.Event, *cloudevents.EventResponse) error } diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/types/allocate.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/types/allocate.go index 00a4870f900..c38f7117701 100644 --- a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/types/allocate.go +++ b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/types/allocate.go @@ -2,7 +2,7 @@ package types import "reflect" -// Allocates allocates a new instance of type t and returns: +// Allocate allocates a new instance of type t and returns: // asPtr is of type t if t is a pointer type and of type &t otherwise // asValue is a Value of type t pointing to the same data as asPtr func Allocate(obj interface{}) (asPtr interface{}, asValue reflect.Value) { From 71f166c52b98f9bee72c8b3ed55f29c7319ebeb8 Mon Sep 17 00:00:00 2001 From: nachocano Date: Thu, 21 Mar 2019 12:58:29 -0700 Subject: [PATCH 167/221] Adding observability --- .../cloudevents/sdk-go/pkg/cloudevents/observability/doc.go | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/observability/doc.go diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/observability/doc.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/observability/doc.go new file mode 100644 index 00000000000..3067ebe7e5d --- /dev/null +++ b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/observability/doc.go @@ -0,0 +1,4 @@ +/* +Package observability holds metrics and tracing recording implementations. +*/ +package observability From e323c7ae8ed3205603c8ae2e73477ece478e5f27 Mon Sep 17 00:00:00 2001 From: nachocano Date: Thu, 21 Mar 2019 13:39:10 -0700 Subject: [PATCH 168/221] validation --- .../eventing/v1alpha1/eventtype_validation.go | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/pkg/apis/eventing/v1alpha1/eventtype_validation.go b/pkg/apis/eventing/v1alpha1/eventtype_validation.go index 2f4419ef089..a24239b827c 100644 --- a/pkg/apis/eventing/v1alpha1/eventtype_validation.go +++ b/pkg/apis/eventing/v1alpha1/eventtype_validation.go @@ -18,6 +18,7 @@ package v1alpha1 import ( "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" "github.com/knative/pkg/apis" ) @@ -25,12 +26,20 @@ func (et *EventType) Validate() *apis.FieldError { return et.Spec.Validate().ViaField("spec") } -func (et *EventTypeSpec) Validate() *apis.FieldError { +func (ets *EventTypeSpec) Validate() *apis.FieldError { var errs *apis.FieldError + if ets.Type == "" { + fe := apis.ErrMissingField("type") + errs = errs.Also(fe) + } + if ets.Broker == "" { + fe := apis.ErrMissingField("broker") + errs = errs.Also(fe) + } return errs } -func (r *EventType) CheckImmutableFields(og apis.Immutable) *apis.FieldError { +func (et *EventType) CheckImmutableFields(og apis.Immutable) *apis.FieldError { if og == nil { return nil } @@ -40,13 +49,16 @@ func (r *EventType) CheckImmutableFields(og apis.Immutable) *apis.FieldError { return &apis.FieldError{Message: "The provided original was not an EventType"} } - // TODO check other fields. - if diff := cmp.Diff(original.Spec.Type, r.Spec.Type); diff != "" { + // TODO should schema be mutable? + // Only Schema is mutable. + ignoreArguments := cmpopts.IgnoreFields(EventTypeSpec{}, "Schema") + if diff := cmp.Diff(original.Spec, et.Spec, ignoreArguments); diff != "" { return &apis.FieldError{ Message: "Immutable fields changed (-old +new)", - Paths: []string{"spec", "events"}, + Paths: []string{"spec"}, Details: diff, } } + return nil } From c07196add0783fdfe0aed2feb9149f316c5b6534 Mon Sep 17 00:00:00 2001 From: nachocano Date: Thu, 21 Mar 2019 13:43:16 -0700 Subject: [PATCH 169/221] broker default --- pkg/apis/eventing/v1alpha1/eventtype_defaults.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/pkg/apis/eventing/v1alpha1/eventtype_defaults.go b/pkg/apis/eventing/v1alpha1/eventtype_defaults.go index 8b29c76df41..8bb0ed98e83 100644 --- a/pkg/apis/eventing/v1alpha1/eventtype_defaults.go +++ b/pkg/apis/eventing/v1alpha1/eventtype_defaults.go @@ -17,9 +17,11 @@ limitations under the License. package v1alpha1 func (et *EventType) SetDefaults() { - et.Spec.SetDefaults(et.Name) + et.Spec.SetDefaults() } -func (ets *EventTypeSpec) SetDefaults(eventTypeName string) { - // TODO anything? +func (ets *EventTypeSpec) SetDefaults() { + if ets.Broker == "" { + ets.Broker = "default" + } } From 08c679c8602ceb7e1b00292ea3cbb0aee79dfb76 Mon Sep 17 00:00:00 2001 From: nachocano Date: Thu, 21 Mar 2019 14:43:22 -0700 Subject: [PATCH 170/221] event type controller... checks for broker existence and readiness --- cmd/controller/main.go | 3 + pkg/apis/eventing/v1alpha1/eventtype_types.go | 44 ++-- .../eventing/v1alpha1/eventtype_validation.go | 5 +- .../v1alpha1/eventtype/eventtype.go | 197 ++++++++++++++++++ 4 files changed, 226 insertions(+), 23 deletions(-) create mode 100644 pkg/reconciler/v1alpha1/eventtype/eventtype.go diff --git a/cmd/controller/main.go b/cmd/controller/main.go index 51339cc291a..7d3cac72002 100644 --- a/cmd/controller/main.go +++ b/cmd/controller/main.go @@ -24,6 +24,8 @@ import ( "os" "time" + "github.com/knative/eventing/pkg/reconciler/v1alpha1/eventtype" + "github.com/knative/eventing/pkg/reconciler/v1alpha1/broker" "github.com/knative/eventing/pkg/reconciler/v1alpha1/channel" "github.com/knative/eventing/pkg/reconciler/v1alpha1/namespace" @@ -134,6 +136,7 @@ func main() { }), trigger.ProvideController, namespace.ProvideController, + eventtype.ProvideController, } for _, provider := range providers { if _, err = provider(mgr, logger.Desugar()); err != nil { diff --git a/pkg/apis/eventing/v1alpha1/eventtype_types.go b/pkg/apis/eventing/v1alpha1/eventtype_types.go index 01f15494107..81bf1bbf035 100644 --- a/pkg/apis/eventing/v1alpha1/eventtype_types.go +++ b/pkg/apis/eventing/v1alpha1/eventtype_types.go @@ -64,34 +64,26 @@ type EventTypeSpec struct { Source string `json:"source,omitempty"` // +optional Schema string `json:"schema,omitempty"` - // TODO sink or broker? string or ref? - // TODO validate that the broker exists + // TODO sink or broker? string or obj ref? Broker string `json:"broker,omitempty"` } -var eventTypeCondSet = duckv1alpha1.NewLivingConditionSet(EventTypeConditionReady) - // EventTypeStatus represents the current state of a EventType. type EventTypeStatus struct { - // ObservedGeneration is the most recent generation observed for this EventType. - // It corresponds to the Broker's generation, which is updated on mutation by - // the API Server. - // TODO: The above comment is only true once - // https://github.com/kubernetes/kubernetes/issues/58778 is fixed. - // +optional - ObservedGeneration int64 `json:"observedGeneration,omitempty"` - - // Represents the latest available observations of a event type's current state. - // +optional - // +patchMergeKey=type - // +patchStrategy=merge - Conditions duckv1alpha1.Conditions `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"` + // inherits duck/v1alpha1 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. + duckv1alpha1.Status `json:",inline"` } const ( - EventTypeConditionReady = duckv1alpha1.ConditionReady + EventTypeConditionReady = duckv1alpha1.ConditionReady + EventTypeConditionBrokerExists duckv1alpha1.ConditionType = "BrokerExists" + EventTypeConditionBrokerReady duckv1alpha1.ConditionType = "BrokerReady" ) +var eventTypeCondSet = duckv1alpha1.NewLivingConditionSet(EventTypeConditionBrokerExists, EventTypeConditionBrokerReady) + // GetCondition returns the condition currently associated with the given type, or nil. func (et *EventTypeStatus) GetCondition(t duckv1alpha1.ConditionType) *duckv1alpha1.Condition { return eventTypeCondSet.Manage(et).GetCondition(t) @@ -107,8 +99,20 @@ func (et *EventTypeStatus) InitializeConditions() { eventTypeCondSet.Manage(et).InitializeConditions() } -func (rs *EventTypeStatus) MarkEventTypeReady() { - eventTypeCondSet.Manage(rs).MarkTrue(EventTypeConditionReady) +func (et *EventTypeStatus) MarkBrokerExists() { + eventTypeCondSet.Manage(et).MarkTrue(EventTypeConditionBrokerExists) +} + +func (et *EventTypeStatus) MarkBrokerDoesNotExist() { + eventTypeCondSet.Manage(et).MarkFalse(EventTypeConditionBrokerExists, "doesNotExist", "Broker does not exist") +} + +func (et *EventTypeStatus) MarkBrokerReady() { + eventTypeCondSet.Manage(et).MarkTrue(EventTypeConditionBrokerReady) +} + +func (et *EventTypeStatus) MarkBrokerNotReady() { + eventTypeCondSet.Manage(et).MarkFalse(EventTypeConditionBrokerReady, "notReady", "Broker is not ready") } // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object diff --git a/pkg/apis/eventing/v1alpha1/eventtype_validation.go b/pkg/apis/eventing/v1alpha1/eventtype_validation.go index a24239b827c..106230eb027 100644 --- a/pkg/apis/eventing/v1alpha1/eventtype_validation.go +++ b/pkg/apis/eventing/v1alpha1/eventtype_validation.go @@ -49,9 +49,8 @@ func (et *EventType) CheckImmutableFields(og apis.Immutable) *apis.FieldError { return &apis.FieldError{Message: "The provided original was not an EventType"} } - // TODO should schema be mutable? - // Only Schema is mutable. - ignoreArguments := cmpopts.IgnoreFields(EventTypeSpec{}, "Schema") + // TODO should schema and broker be mutable? + ignoreArguments := cmpopts.IgnoreFields(EventTypeSpec{}, "Schema", "Broker") if diff := cmp.Diff(original.Spec, et.Spec, ignoreArguments); diff != "" { return &apis.FieldError{ Message: "Immutable fields changed (-old +new)", diff --git a/pkg/reconciler/v1alpha1/eventtype/eventtype.go b/pkg/reconciler/v1alpha1/eventtype/eventtype.go new file mode 100644 index 00000000000..abcff003645 --- /dev/null +++ b/pkg/reconciler/v1alpha1/eventtype/eventtype.go @@ -0,0 +1,197 @@ +/* +Copyright 2019 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT 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 eventtype + +import ( + "context" + + "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" + "github.com/knative/eventing/pkg/logging" + "go.uber.org/zap" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/equality" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/dynamic" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/record" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller" + "sigs.k8s.io/controller-runtime/pkg/handler" + "sigs.k8s.io/controller-runtime/pkg/manager" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + "sigs.k8s.io/controller-runtime/pkg/source" +) + +const ( + // controllerAgentName is the string used by this controller to identify + // itself when creating events. + controllerAgentName = "eventtype-controller" + + // Name of the corev1.Events emitted from the reconciliation process. + eventTypeReconciled = "EventTypeReconciled" + eventTypeReconcileFailed = "EventTypeReconcileFailed" + eventTypeUpdateStatusFailed = "EventTypeUpdateStatusFailed" +) + +type reconciler struct { + client client.Client + dynamicClient dynamic.Interface + recorder record.EventRecorder + + logger *zap.Logger +} + +// Verify the struct implements reconcile.Reconciler. +var _ reconcile.Reconciler = &reconciler{} + +// ProvideController returns a function that returns an EventType controller. +func ProvideController(mgr manager.Manager, logger *zap.Logger) (controller.Controller, error) { + // Setup a new controller to Reconcile EventTypes. + r := &reconciler{ + recorder: mgr.GetRecorder(controllerAgentName), + logger: logger, + } + c, err := controller.New(controllerAgentName, mgr, controller.Options{ + Reconciler: r, + }) + if err != nil { + return nil, err + } + + // Watch EventTypes. + if err = c.Watch(&source.Kind{Type: &v1alpha1.EventType{}}, &handler.EnqueueRequestForObject{}); err != nil { + return nil, err + } + + // TODO watch for broker changes + return c, nil +} + +func (r *reconciler) InjectClient(c client.Client) error { + r.client = c + return nil +} + +func (r *reconciler) InjectConfig(c *rest.Config) error { + var err error + r.dynamicClient, err = dynamic.NewForConfig(c) + return err +} + +// Reconcile compares the actual state with the desired, and attempts to +// converge the two. It then updates the Status block of the EventType resource +// with the current status of the resource. +func (r *reconciler) Reconcile(request reconcile.Request) (reconcile.Result, error) { + ctx := context.TODO() + ctx = logging.WithLogger(ctx, r.logger.With(zap.Any("request", request))) + + eventType := &v1alpha1.EventType{} + err := r.client.Get(ctx, request.NamespacedName, eventType) + + if errors.IsNotFound(err) { + logging.FromContext(ctx).Info("Could not find EventType") + return reconcile.Result{}, nil + } + + if err != nil { + logging.FromContext(ctx).Error("Could not get EventType", zap.Error(err)) + return reconcile.Result{}, err + } + + // Reconcile this copy of the EventType and then write back any status updates regardless of + // whether the reconcile error out. + reconcileErr := r.reconcile(ctx, eventType) + if reconcileErr != nil { + logging.FromContext(ctx).Error("Error reconciling EventType", zap.Error(reconcileErr)) + r.recorder.Eventf(eventType, corev1.EventTypeWarning, eventTypeReconcileFailed, "EventType reconciliation failed: %v", reconcileErr) + } else { + logging.FromContext(ctx).Debug("EventType reconciled") + r.recorder.Event(eventType, corev1.EventTypeNormal, eventTypeReconciled, "EventType reconciled") + } + + if _, err = r.updateStatus(eventType); err != nil { + logging.FromContext(ctx).Error("Failed to update EventType status", zap.Error(err)) + r.recorder.Eventf(eventType, corev1.EventTypeWarning, eventTypeUpdateStatusFailed, "Failed to update EventType's status: %v", err) + return reconcile.Result{}, err + } + + // Requeue if the resource is not ready + return reconcile.Result{}, reconcileErr +} + +func (r *reconciler) reconcile(ctx context.Context, et *v1alpha1.EventType) error { + et.Status.InitializeConditions() + + // 1. Verify the Broker exists. + // 2. Verify the Broker is ready. + + if et.DeletionTimestamp != nil { + // Everything is cleaned up by the garbage collector. + return nil + } + + b, err := r.getBroker(ctx, et) + if err != nil { + logging.FromContext(ctx).Error("Unable to get the Broker", zap.Error(err)) + et.Status.MarkBrokerDoesNotExist() + return err + } + et.Status.MarkBrokerExists() + + if !b.Status.IsReady() { + logging.FromContext(ctx).Error("Broker is not ready", zap.Error(err)) + et.Status.MarkBrokerNotReady() + return err + } + et.Status.MarkBrokerReady() + + return nil +} + +// updateStatus updates the event type's status. +func (r *reconciler) updateStatus(eventType *v1alpha1.EventType) (*v1alpha1.EventType, error) { + ctx := context.TODO() + objectKey := client.ObjectKey{Namespace: eventType.Namespace, Name: eventType.Name} + latestEventType := &v1alpha1.EventType{} + + if err := r.client.Get(ctx, objectKey, latestEventType); err != nil { + return nil, err + } + + if equality.Semantic.DeepEqual(latestEventType.Status, eventType.Status) { + return eventType, nil + } + + latestEventType.Status = eventType.Status + if err := r.client.Status().Update(ctx, latestEventType); err != nil { + return nil, err + } + + return latestEventType, nil +} + +// getBroker returns the Broker for EventType 'et' if exists, otherwise it returns an error. +func (r *reconciler) getBroker(ctx context.Context, et *v1alpha1.EventType) (*v1alpha1.Broker, error) { + b := &v1alpha1.Broker{} + name := types.NamespacedName{ + Namespace: et.Namespace, + Name: et.Spec.Broker, + } + err := r.client.Get(ctx, name, b) + return b, err +} From c01af03a6417c0ad956dc28c91798c55babde12d Mon Sep 17 00:00:00 2001 From: nachocano Date: Thu, 21 Mar 2019 14:44:19 -0700 Subject: [PATCH 171/221] adding extra columns --- config/300-eventtype.yaml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/config/300-eventtype.yaml b/config/300-eventtype.yaml index 26ce91117a5..ba1ebabe7b4 100644 --- a/config/300-eventtype.yaml +++ b/config/300-eventtype.yaml @@ -36,9 +36,15 @@ spec: - name: Source type: string JSONPath: ".spec.source" + - name: Schema + type: string + JSONPath: ".spec.schema" - name: Broker type: string JSONPath: ".spec.broker" - - name: Schema + - name: Ready type: string - JSONPath: ".spec.schema" + JSONPath: ".status.conditions[?(@.type==\"Ready\")].status" + - name: Reason + type: string + JSONPath: ".status.conditions[?(@.type==\"Ready\")].reason" From 021706110560c65a06a9e5370e8bab53defb47a0 Mon Sep 17 00:00:00 2001 From: nachocano Date: Thu, 21 Mar 2019 14:46:38 -0700 Subject: [PATCH 172/221] message in columns --- pkg/apis/eventing/v1alpha1/eventtype_types.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/apis/eventing/v1alpha1/eventtype_types.go b/pkg/apis/eventing/v1alpha1/eventtype_types.go index 81bf1bbf035..29965b2c93f 100644 --- a/pkg/apis/eventing/v1alpha1/eventtype_types.go +++ b/pkg/apis/eventing/v1alpha1/eventtype_types.go @@ -104,7 +104,7 @@ func (et *EventTypeStatus) MarkBrokerExists() { } func (et *EventTypeStatus) MarkBrokerDoesNotExist() { - eventTypeCondSet.Manage(et).MarkFalse(EventTypeConditionBrokerExists, "doesNotExist", "Broker does not exist") + eventTypeCondSet.Manage(et).MarkFalse(EventTypeConditionBrokerExists, "BrokerDoesNotExist", "Broker does not exist") } func (et *EventTypeStatus) MarkBrokerReady() { @@ -112,7 +112,7 @@ func (et *EventTypeStatus) MarkBrokerReady() { } func (et *EventTypeStatus) MarkBrokerNotReady() { - eventTypeCondSet.Manage(et).MarkFalse(EventTypeConditionBrokerReady, "notReady", "Broker is not ready") + eventTypeCondSet.Manage(et).MarkFalse(EventTypeConditionBrokerReady, "BrokerNotReady", "Broker is not ready") } // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object From ea1d272b801ee94eed72c2314fa73105082acdcd Mon Sep 17 00:00:00 2001 From: nachocano Date: Thu, 21 Mar 2019 15:55:41 -0700 Subject: [PATCH 173/221] Passing broker. Need to refactor this module --- cmd/broker/ingress/main.go | 5 ++++- pkg/broker/ingress.go | 42 ++++++++++++++++++++++++-------------- 2 files changed, 31 insertions(+), 16 deletions(-) diff --git a/cmd/broker/ingress/main.go b/cmd/broker/ingress/main.go index 19b71b350f3..284c293f860 100644 --- a/cmd/broker/ingress/main.go +++ b/cmd/broker/ingress/main.go @@ -120,7 +120,10 @@ func New(logger *zap.Logger, channelURI *url.URL, client client.Client, namespac if err != nil { return nil, err } - ingressPolicy := broker.NewIngressPolicy(logger, client, namespace, policy) + // TODO pass broker. + // Waiting on https://github.com/knative/eventing/pull/937 + // which passes the broker name as an env variable. + ingressPolicy := broker.NewIngressPolicy(logger, client, namespace, "", policy) return &handler{ logger: logger, diff --git a/pkg/broker/ingress.go b/pkg/broker/ingress.go index c5da8ff4baa..eb9e2a7d4fe 100644 --- a/pkg/broker/ingress.go +++ b/pkg/broker/ingress.go @@ -22,6 +22,8 @@ import ( "regexp" "strings" + "k8s.io/apimachinery/pkg/labels" + "go.uber.org/zap" "k8s.io/apimachinery/pkg/util/validation" @@ -38,6 +40,9 @@ const ( allowAny = "allow_any" allowRegisteredTypes = "allow_registered" autoCreate = "auto_create" + + // Label to get the event types for a particular Broker. + eventingEventTypeBrokerLabelKey = "eventing.knative.dev/eventtype-broker" ) var ( @@ -57,31 +62,35 @@ type Registered struct { logger *zap.SugaredLogger client client.Client namespace string + broker string } type AutoCreate struct { logger *zap.SugaredLogger client client.Client namespace string + broker string } -func NewIngressPolicy(logger *zap.Logger, client client.Client, namespace, policy string) IngressPolicy { - return newIngressPolicy(logger.Sugar(), client, namespace, policy) +func NewIngressPolicy(logger *zap.Logger, client client.Client, namespace, broker, policy string) IngressPolicy { + return newIngressPolicy(logger.Sugar(), client, namespace, broker, policy) } -func newIngressPolicy(logger *zap.SugaredLogger, client client.Client, namespace, policy string) IngressPolicy { +func newIngressPolicy(logger *zap.SugaredLogger, client client.Client, namespace, broker, policy string) IngressPolicy { switch policy { case allowRegisteredTypes: return &Registered{ logger: logger, client: client, namespace: namespace, + broker: broker, } case autoCreate: return &AutoCreate{ logger: logger, client: client, namespace: namespace, + broker: broker, } case allowAny: return &Any{} @@ -95,7 +104,7 @@ func (p *Any) AllowEvent(event *cloudevents.Event) bool { } func (p *Registered) AllowEvent(event *cloudevents.Event) bool { - _, err := getEventType(p.client, event, p.namespace) + _, err := getEventType(p.client, event, p.namespace, p.broker) if k8serrors.IsNotFound(err) { p.logger.Warnf("EventType not found, rejecting spec.type %q, %v", event.Type(), err) return false @@ -107,10 +116,10 @@ func (p *Registered) AllowEvent(event *cloudevents.Event) bool { } func (p *AutoCreate) AllowEvent(event *cloudevents.Event) bool { - _, err := getEventType(p.client, event, p.namespace) + _, err := getEventType(p.client, event, p.namespace, p.broker) if k8serrors.IsNotFound(err) { p.logger.Infof("EventType not found, creating spec.type %q", event.Type()) - eventType := makeEventType(event, p.namespace) + eventType := makeEventType(event, p.namespace, p.broker) err := p.client.Create(context.TODO(), eventType) if err != nil { p.logger.Errorf("Error creating EventType, spec.type %q, %v", event.Type(), err) @@ -121,10 +130,10 @@ func (p *AutoCreate) AllowEvent(event *cloudevents.Event) bool { return true } -func getEventType(c client.Client, event *cloudevents.Event, namespace string) (*eventingv1alpha1.EventType, error) { +func getEventType(c client.Client, event *cloudevents.Event, namespace, broker string) (*eventingv1alpha1.EventType, error) { opts := &client.ListOptions{ - Namespace: namespace, - // TODO add label selector on broker name. + Namespace: namespace, + LabelSelector: labels.SelectorFromSet(eventTypeLabels(broker)), // Set Raw because if we need to get more than one page, then we will put the continue token // into opts.Raw.Continue. Raw: &metav1.ListOptions{}, @@ -154,22 +163,19 @@ func getEventType(c client.Client, event *cloudevents.Event, namespace string) ( } // makeEventType generates, but does not create an EventType from the given cloudevents.Event. -func makeEventType(event *cloudevents.Event, namespace string) *eventingv1alpha1.EventType { +func makeEventType(event *cloudevents.Event, namespace, broker string) *eventingv1alpha1.EventType { cloudEventType := event.Type() return &eventingv1alpha1.EventType{ ObjectMeta: metav1.ObjectMeta{ GenerateName: fmt.Sprintf("%s-", toValidIdentifier(cloudEventType)), Namespace: namespace, - // TODO add broker label - // Waiting on https://github.com/knative/eventing/pull/937 - // which passes the broker name as an env variable. + Labels: eventTypeLabels(broker), }, Spec: eventingv1alpha1.EventTypeSpec{ Type: cloudEventType, Source: event.Source(), Schema: event.SchemaURL(), - // Waiting on https://github.com/knative/eventing/pull/937 - Broker: "", + Broker: broker, }, } } @@ -184,3 +190,9 @@ func toValidIdentifier(cloudEventType string) string { } return cloudEventType } + +func eventTypeLabels(broker string) map[string]string { + return map[string]string{ + eventingEventTypeBrokerLabelKey: broker, + } +} From ea4a531cd617872b339685bfb5e2cf8ff8709b46 Mon Sep 17 00:00:00 2001 From: nachocano Date: Thu, 21 Mar 2019 16:02:12 -0700 Subject: [PATCH 174/221] broker immutable to avoid problem with label selector --- pkg/apis/eventing/v1alpha1/eventtype_validation.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pkg/apis/eventing/v1alpha1/eventtype_validation.go b/pkg/apis/eventing/v1alpha1/eventtype_validation.go index 547d9c08e2d..0617185c4f9 100644 --- a/pkg/apis/eventing/v1alpha1/eventtype_validation.go +++ b/pkg/apis/eventing/v1alpha1/eventtype_validation.go @@ -51,8 +51,9 @@ func (et *EventType) CheckImmutableFields(ctx context.Context, og apis.Immutable return &apis.FieldError{Message: "The provided original was not an EventType"} } - // TODO should schema and broker be mutable? - ignoreArguments := cmpopts.IgnoreFields(EventTypeSpec{}, "Schema", "Broker") + // TODO should schema be mutable? + // If we make broker mutable, then we might have problems with the label selectors. + ignoreArguments := cmpopts.IgnoreFields(EventTypeSpec{}, "Schema") if diff := cmp.Diff(original.Spec, et.Spec, ignoreArguments); diff != "" { return &apis.FieldError{ Message: "Immutable fields changed (-old +new)", From 4537b4430f880bf0a03a6e4a717062f2d3636b17 Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Thu, 21 Mar 2019 20:13:20 -0700 Subject: [PATCH 175/221] listening for broker changes --- .../v1alpha1/eventtype/eventtype.go | 47 ++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/pkg/reconciler/v1alpha1/eventtype/eventtype.go b/pkg/reconciler/v1alpha1/eventtype/eventtype.go index abcff003645..0efe509885b 100644 --- a/pkg/reconciler/v1alpha1/eventtype/eventtype.go +++ b/pkg/reconciler/v1alpha1/eventtype/eventtype.go @@ -25,6 +25,7 @@ import ( corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/equality" "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/dynamic" "k8s.io/client-go/rest" @@ -78,10 +79,54 @@ func ProvideController(mgr manager.Manager, logger *zap.Logger) (controller.Cont return nil, err } - // TODO watch for broker changes + // Watch for Broker changes. E.g. if the Broker is deleted, we need to reconcile its EventTypes again. + if err = c.Watch(&source.Kind{Type: &v1alpha1.Broker{}}, &handler.EnqueueRequestsFromMapFunc{ToRequests: &mapBrokerToEventTypes{r: r}}); err != nil { + return nil, err + } + return c, nil } +// mapBrokerToEventTypes maps Broker changes to all the EventTypes that correspond to that Broker. +type mapBrokerToEventTypes struct { + r *reconciler +} + +func (b *mapBrokerToEventTypes) Map(o handler.MapObject) []reconcile.Request { + ctx := context.Background() + eventTypes := make([]reconcile.Request, 0) + + opts := &client.ListOptions{ + Namespace: o.Meta.GetNamespace(), + // Set Raw because if we need to get more than one page, then we will put the continue token + // into opts.Raw.Continue. + Raw: &metav1.ListOptions{}, + } + for { + etl := &v1alpha1.EventTypeList{} + if err := b.r.client.List(ctx, opts, etl); err != nil { + b.r.logger.Error("Error listing EventTypes when Broker changed. Some EventTypes may not be reconciled.", zap.Error(err), zap.Any("broker", o)) + return eventTypes + } + + for _, et := range etl.Items { + if et.Spec.Broker == o.Meta.GetName() { + eventTypes = append(eventTypes, reconcile.Request{ + NamespacedName: types.NamespacedName{ + Namespace: et.Namespace, + Name: et.Name, + }, + }) + } + } + if etl.Continue != "" { + opts.Raw.Continue = etl.Continue + } else { + return eventTypes + } + } +} + func (r *reconciler) InjectClient(c client.Client) error { r.client = c return nil From 35d00953a61b03cf7fc669c8a89686b3f3364395 Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Thu, 21 Mar 2019 20:36:30 -0700 Subject: [PATCH 176/221] removing broker label. Making broker mutable again. --- .../eventing/v1alpha1/eventtype_validation.go | 5 ++- pkg/broker/ingress.go | 34 +++++++------------ 2 files changed, 14 insertions(+), 25 deletions(-) diff --git a/pkg/apis/eventing/v1alpha1/eventtype_validation.go b/pkg/apis/eventing/v1alpha1/eventtype_validation.go index 0617185c4f9..9b5303538f7 100644 --- a/pkg/apis/eventing/v1alpha1/eventtype_validation.go +++ b/pkg/apis/eventing/v1alpha1/eventtype_validation.go @@ -51,9 +51,8 @@ func (et *EventType) CheckImmutableFields(ctx context.Context, og apis.Immutable return &apis.FieldError{Message: "The provided original was not an EventType"} } - // TODO should schema be mutable? - // If we make broker mutable, then we might have problems with the label selectors. - ignoreArguments := cmpopts.IgnoreFields(EventTypeSpec{}, "Schema") + // Schema and Broker mutable. + ignoreArguments := cmpopts.IgnoreFields(EventTypeSpec{}, "Schema", "Broker") if diff := cmp.Diff(original.Spec, et.Spec, ignoreArguments); diff != "" { return &apis.FieldError{ Message: "Immutable fields changed (-old +new)", diff --git a/pkg/broker/ingress.go b/pkg/broker/ingress.go index eb9e2a7d4fe..dee570fba2c 100644 --- a/pkg/broker/ingress.go +++ b/pkg/broker/ingress.go @@ -22,8 +22,6 @@ import ( "regexp" "strings" - "k8s.io/apimachinery/pkg/labels" - "go.uber.org/zap" "k8s.io/apimachinery/pkg/util/validation" @@ -132,8 +130,7 @@ func (p *AutoCreate) AllowEvent(event *cloudevents.Event) bool { func getEventType(c client.Client, event *cloudevents.Event, namespace, broker string) (*eventingv1alpha1.EventType, error) { opts := &client.ListOptions{ - Namespace: namespace, - LabelSelector: labels.SelectorFromSet(eventTypeLabels(broker)), + Namespace: namespace, // Set Raw because if we need to get more than one page, then we will put the continue token // into opts.Raw.Continue. Raw: &metav1.ListOptions{}, @@ -142,20 +139,21 @@ func getEventType(c client.Client, event *cloudevents.Event, namespace, broker s ctx := context.TODO() for { - el := &eventingv1alpha1.EventTypeList{} - err := c.List(ctx, opts, el) + etl := &eventingv1alpha1.EventTypeList{} + err := c.List(ctx, opts, etl) if err != nil { return nil, err } - for _, e := range el.Items { - // TODO what about source? - if e.Spec.Type == event.Type() && e.Spec.Schema == event.SchemaURL() { - return &e, nil + for _, et := range etl.Items { + if et.Spec.Broker == broker { + // TODO what about source. + if et.Spec.Type == event.Type() && et.Spec.Schema == event.SchemaURL() { + return &et, nil + } } - } - if el.Continue != "" { - opts.Raw.Continue = el.Continue + if etl.Continue != "" { + opts.Raw.Continue = etl.Continue } else { return nil, notFound } @@ -169,7 +167,6 @@ func makeEventType(event *cloudevents.Event, namespace, broker string) *eventing ObjectMeta: metav1.ObjectMeta{ GenerateName: fmt.Sprintf("%s-", toValidIdentifier(cloudEventType)), Namespace: namespace, - Labels: eventTypeLabels(broker), }, Spec: eventingv1alpha1.EventTypeSpec{ Type: cloudEventType, @@ -180,19 +177,12 @@ func makeEventType(event *cloudevents.Event, namespace, broker string) *eventing } } -// TODO some utility to also be used from eventing-sources. func toValidIdentifier(cloudEventType string) string { + // If it is not a valid DNS1123 name, make it a valid one. if msgs := validation.IsDNS1123Subdomain(cloudEventType); len(msgs) != 0 { - // If it is not a valid DNS1123 name, make it a valid one. // TODO take care of size < 63, and starting and end indexes should be alphanumeric. cloudEventType = strings.ToLower(cloudEventType) cloudEventType = validChars.ReplaceAllString(cloudEventType, "") } return cloudEventType } - -func eventTypeLabels(broker string) map[string]string { - return map[string]string{ - eventingEventTypeBrokerLabelKey: broker, - } -} From 71638f0a6ec6b24a6e69b90a359ea102411c83af Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Thu, 21 Mar 2019 21:41:50 -0700 Subject: [PATCH 177/221] fixing dns subdomain --- pkg/broker/ingress.go | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/pkg/broker/ingress.go b/pkg/broker/ingress.go index dee570fba2c..466d1717910 100644 --- a/pkg/broker/ingress.go +++ b/pkg/broker/ingress.go @@ -38,9 +38,6 @@ const ( allowAny = "allow_any" allowRegisteredTypes = "allow_registered" autoCreate = "auto_create" - - // Label to get the event types for a particular Broker. - eventingEventTypeBrokerLabelKey = "eventing.knative.dev/eventtype-broker" ) var ( @@ -165,7 +162,7 @@ func makeEventType(event *cloudevents.Event, namespace, broker string) *eventing cloudEventType := event.Type() return &eventingv1alpha1.EventType{ ObjectMeta: metav1.ObjectMeta{ - GenerateName: fmt.Sprintf("%s-", toValidIdentifier(cloudEventType)), + GenerateName: fmt.Sprintf("%s-", toDNS1123Subdomain(cloudEventType)), Namespace: namespace, }, Spec: eventingv1alpha1.EventTypeSpec{ @@ -177,12 +174,17 @@ func makeEventType(event *cloudevents.Event, namespace, broker string) *eventing } } -func toValidIdentifier(cloudEventType string) string { - // If it is not a valid DNS1123 name, make it a valid one. +func toDNS1123Subdomain(cloudEventType string) string { + // If it is not a valid DNS1123 subdomain, make it a valid one. if msgs := validation.IsDNS1123Subdomain(cloudEventType); len(msgs) != 0 { - // TODO take care of size < 63, and starting and end indexes should be alphanumeric. + // If the length exceeds the max, cut it and leave some room for the generated UUID. + if len(cloudEventType) > validation.DNS1123SubdomainMaxLength { + cloudEventType = cloudEventType[:validation.DNS1123SubdomainMaxLength-10] + } cloudEventType = strings.ToLower(cloudEventType) cloudEventType = validChars.ReplaceAllString(cloudEventType, "") + // Only start/end with alphanumeric. + cloudEventType = strings.Trim(cloudEventType, "-.") } return cloudEventType } From be11e6c858406c428f838d68379b453b82875c11 Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Fri, 22 Mar 2019 00:31:47 -0700 Subject: [PATCH 178/221] ingress policy as an object. adding some UTs. still not convinced. --- cmd/broker/ingress/main.go | 42 +++--- docs/registry/example_broker_policies.yaml | 14 +- docs/registry/example_eventtype.yaml | 2 +- pkg/apis/eventing/v1alpha1/broker_defaults.go | 7 +- .../eventing/v1alpha1/broker_defaults_test.go | 63 ++++++++- pkg/apis/eventing/v1alpha1/broker_types.go | 8 +- .../eventing/v1alpha1/broker_validation.go | 9 +- .../v1alpha1/broker_validation_test.go | 45 ++++++- pkg/apis/eventing/v1alpha1/eventtype_types.go | 3 +- pkg/broker/ingress.go | 122 +++++++----------- .../v1alpha1/broker/resources/ingress.go | 13 +- 11 files changed, 214 insertions(+), 114 deletions(-) diff --git a/cmd/broker/ingress/main.go b/cmd/broker/ingress/main.go index 2fb15d4084f..bbb0c3ad478 100644 --- a/cmd/broker/ingress/main.go +++ b/cmd/broker/ingress/main.go @@ -24,13 +24,15 @@ import ( "net/http" "net/url" "os" + "strconv" "time" + "github.com/knative/eventing/pkg/broker" + "github.com/cloudevents/sdk-go/pkg/cloudevents" ceclient "github.com/cloudevents/sdk-go/pkg/cloudevents/client" cehttp "github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http" eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" - "github.com/knative/eventing/pkg/broker" "github.com/knative/eventing/pkg/provisioners" "github.com/knative/pkg/signals" "go.uber.org/zap" @@ -38,12 +40,6 @@ import ( "sigs.k8s.io/controller-runtime/pkg/manager" ) -const ( - NAMESPACE = "NAMESPACE" - CHANNEL = "CHANNEL" - POLICY = "POLICY" -) - var ( defaultPort = 8080 @@ -58,7 +54,7 @@ func main() { logger.Info("Starting...") - namespace := getRequiredEnv(NAMESPACE) + namespace := getRequiredEnv("NAMESPACE") mgr, err := manager.New(config.GetConfigOrDie(), manager.Options{ Namespace: namespace, @@ -73,17 +69,19 @@ func main() { channelURI := &url.URL{ Scheme: "http", - Host: getRequiredEnv(CHANNEL), + Host: getRequiredEnv("CHANNEL"), Path: "/", } client := mgr.GetClient() - p := getRequiredEnv(POLICY) - // TODO pass broker. - // Waiting on https://github.com/knative/eventing/pull/937 - // which passes the broker name as an env variable. - ingressPolicy := broker.NewIngressPolicy(logger, client, namespace, "", p) + policySpec := &eventingv1alpha1.IngressPolicySpec{ + AllowAny: asBool(getRequiredEnv("POLICY_ALLOW_ANY")), + AutoAdd: asBool(getRequiredEnv("POLICY_AUTO_ADD")), + } + brokerName := getRequiredEnv("BROKER") + + ingressPolicy := broker.NewPolicy(logger, client, policySpec, namespace, brokerName) // Create an event handler. ceHTTP, err := cehttp.New(cehttp.WithBinaryEncoding(), cehttp.WithPort(defaultPort)) @@ -127,12 +125,20 @@ func getRequiredEnv(envKey string) string { return val } +func asBool(envVal string) bool { + b, err := strconv.ParseBool(envVal) + if err != nil { + log.Fatalf("required environment variable not bool %q", envVal) + } + return b +} + type handler struct { logger *zap.Logger ceClient ceclient.Client ceHTTP *cehttp.Transport channelURI *url.URL - ingressPolicy broker.IngressPolicy + ingressPolicy *broker.IngressPolicy } func (h *handler) Start(stopCh <-chan struct{}) error { @@ -176,12 +182,16 @@ func (h *handler) serveHTTP(ctx context.Context, event cloudevents.Event, resp * return nil } - if h.ingressPolicy.AllowEvent(&event) { + if h.allowEvent(ctx, event) { return h.sendEvent(ctx, tctx, event) } return nil } +func (h *handler) allowEvent(ctx context.Context, event cloudevents.Event) bool { + return h.ingressPolicy.AllowEvent(ctx, &event) +} + func (h *handler) sendEvent(ctx context.Context, tctx cehttp.TransportContext, event cloudevents.Event) error { sendingCTX := broker.SendingContext(ctx, tctx, h.channelURI) _, err := h.ceHTTP.Send(sendingCTX, event) diff --git a/docs/registry/example_broker_policies.yaml b/docs/registry/example_broker_policies.yaml index f98b2275f0b..8badaa10e9f 100644 --- a/docs/registry/example_broker_policies.yaml +++ b/docs/registry/example_broker_policies.yaml @@ -1,24 +1,24 @@ apiVersion: eventing.knative.dev/v1alpha1 kind: Broker metadata: - name: broker-any -spec: - ingressPolicy: allow_any + name: broker-allow-any --- apiVersion: eventing.knative.dev/v1alpha1 kind: Broker metadata: - name: broker-registered + name: broker-allow-registered spec: - ingressPolicy: allow_registered + ingressPolicy: + allowAny: false --- apiVersion: eventing.knative.dev/v1alpha1 kind: Broker metadata: - name: broker-auto-create + name: broker-auto-add spec: - ingressPolicy: auto_create + ingressPolicy: + autoAdd: true diff --git a/docs/registry/example_eventtype.yaml b/docs/registry/example_eventtype.yaml index 75f9ded34a1..8c4ded6fde4 100644 --- a/docs/registry/example_eventtype.yaml +++ b/docs/registry/example_eventtype.yaml @@ -8,4 +8,4 @@ spec: type: repo:push source: user/repo schema: http://schemas/repo/push - broker: broker-any + broker: broker-allow-any diff --git a/pkg/apis/eventing/v1alpha1/broker_defaults.go b/pkg/apis/eventing/v1alpha1/broker_defaults.go index 6351fea1a2c..2cada7abaa0 100644 --- a/pkg/apis/eventing/v1alpha1/broker_defaults.go +++ b/pkg/apis/eventing/v1alpha1/broker_defaults.go @@ -23,5 +23,10 @@ func (b *Broker) SetDefaults(ctx context.Context) { } func (bs *BrokerSpec) SetDefaults(ctx context.Context) { - // None + if bs.IngressPolicy == nil { + bs.IngressPolicy = &IngressPolicySpec{ + AllowAny: true, + AutoAdd: false, + } + } } diff --git a/pkg/apis/eventing/v1alpha1/broker_defaults_test.go b/pkg/apis/eventing/v1alpha1/broker_defaults_test.go index f8dc1302150..7924457b1e3 100644 --- a/pkg/apis/eventing/v1alpha1/broker_defaults_test.go +++ b/pkg/apis/eventing/v1alpha1/broker_defaults_test.go @@ -19,10 +19,67 @@ package v1alpha1 import ( "context" "testing" + + "github.com/google/go-cmp/cmp" ) -// No-op test because method does nothing. func TestBrokerDefaults(t *testing.T) { - b := Broker{} - b.SetDefaults(context.TODO()) + testCases := map[string]struct { + initial Broker + expected Broker + }{ + "nil ingress": { + initial: Broker{}, + expected: Broker{ + Spec: BrokerSpec{ + IngressPolicy: &IngressPolicySpec{ + AllowAny: true, + AutoAdd: false, + }, + }, + }, + }, + "auto add not set": { + initial: Broker{ + Spec: BrokerSpec{ + IngressPolicy: &IngressPolicySpec{ + AllowAny: true, + }, + }, + }, + expected: Broker{ + Spec: BrokerSpec{ + IngressPolicy: &IngressPolicySpec{ + AllowAny: true, + AutoAdd: false, + }, + }, + }, + }, + "allow any not set": { + initial: Broker{ + Spec: BrokerSpec{ + IngressPolicy: &IngressPolicySpec{ + AutoAdd: true, + }, + }, + }, + expected: Broker{ + Spec: BrokerSpec{ + IngressPolicy: &IngressPolicySpec{ + AllowAny: false, + AutoAdd: true, + }, + }, + }, + }, + } + 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/v1alpha1/broker_types.go b/pkg/apis/eventing/v1alpha1/broker_types.go index ce084bef820..3e67754d348 100644 --- a/pkg/apis/eventing/v1alpha1/broker_types.go +++ b/pkg/apis/eventing/v1alpha1/broker_types.go @@ -65,9 +65,13 @@ type BrokerSpec struct { // +optional ChannelTemplate *ChannelSpec `json:"channelTemplate,omitempty"` - // TODO probably make it an object. // +optional - IngressPolicy string `json:"ingressPolicy,omitempty"` + IngressPolicy *IngressPolicySpec `json:"ingressPolicy,omitempty"` +} + +type IngressPolicySpec struct { + AllowAny bool `json:"allowAny,omitempty"` + AutoAdd bool `json:"autoAdd,omitempty"` } var brokerCondSet = duckv1alpha1.NewLivingConditionSet( diff --git a/pkg/apis/eventing/v1alpha1/broker_validation.go b/pkg/apis/eventing/v1alpha1/broker_validation.go index 9f3b4d81f1b..72739a7e39d 100644 --- a/pkg/apis/eventing/v1alpha1/broker_validation.go +++ b/pkg/apis/eventing/v1alpha1/broker_validation.go @@ -18,6 +18,7 @@ package v1alpha1 import ( "context" + "github.com/knative/pkg/apis" ) @@ -26,8 +27,13 @@ func (b *Broker) Validate(ctx context.Context) *apis.FieldError { } func (bs *BrokerSpec) Validate(ctx context.Context) *apis.FieldError { + var errs *apis.FieldError + if bs.IngressPolicy == nil { + fe := apis.ErrMissingField("ingressPolicy") + errs = errs.Also(fe) + } // TODO validate that the channelTemplate only specifies the provisioner and arguments. - return nil + return errs } func (b *Broker) CheckImmutableFields(ctx context.Context, og apis.Immutable) *apis.FieldError { @@ -35,5 +41,6 @@ func (b *Broker) CheckImmutableFields(ctx context.Context, og apis.Immutable) *a // changing it will normally not have the desired effect of changing the Channel inside the // Broker. It would have an effect if the existing Channel was then deleted, the newly created // Channel would use the new spec.channelTemplate. + // Similar thing would happen with spec.ingressPolicy. return nil } diff --git a/pkg/apis/eventing/v1alpha1/broker_validation_test.go b/pkg/apis/eventing/v1alpha1/broker_validation_test.go index 9d737bf3173..795b4117cc0 100644 --- a/pkg/apis/eventing/v1alpha1/broker_validation_test.go +++ b/pkg/apis/eventing/v1alpha1/broker_validation_test.go @@ -19,18 +19,51 @@ package v1alpha1 import ( "context" "testing" + + "github.com/google/go-cmp/cmp" + "github.com/knative/pkg/apis" ) -// No-op test because method does nothing. func TestBrokerValidation(t *testing.T) { - b := Broker{} - _ = b.Validate(context.TODO()) + name := "invalid ingress policy spec" + broker := &Broker{Spec: BrokerSpec{}} + + want := &apis.FieldError{ + Paths: []string{"spec.ingressPolicy"}, + Message: "missing field(s)", + } + + t.Run(name, func(t *testing.T) { + got := broker.Validate(context.TODO()) + if diff := cmp.Diff(want.Error(), got.Error()); diff != "" { + t.Errorf("Broker.Validate (-want, +got) = %v", diff) + } + }) } -// No-op test because method does nothing. func TestBrokerSpecValidation(t *testing.T) { - bs := BrokerSpec{} - _ = bs.Validate(context.TODO()) + tests := []struct { + name string + bs *BrokerSpec + want *apis.FieldError + }{{ + name: "invalid broker spec", + bs: &BrokerSpec{}, + want: func() *apis.FieldError { + fe := apis.ErrMissingField("ingressPolicy") + return fe + }(), + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := test.bs.Validate(context.TODO()) + if diff := cmp.Diff(test.want.Error(), got.Error()); diff != "" { + t.Errorf("%s: Validate BrokerSpec (-want, +got) = %v", test.name, diff) + } + }) + } } // No-op test because method does nothing. diff --git a/pkg/apis/eventing/v1alpha1/eventtype_types.go b/pkg/apis/eventing/v1alpha1/eventtype_types.go index 29965b2c93f..6c03ac44e70 100644 --- a/pkg/apis/eventing/v1alpha1/eventtype_types.go +++ b/pkg/apis/eventing/v1alpha1/eventtype_types.go @@ -58,13 +58,12 @@ type EventTypeSpec struct { // +optional DeprecatedGeneration int64 `json:"generation,omitempty"` - // TODO these attributes may need to be updated once we agree on the object model. Type string `json:"type,omitempty"` // +optional Source string `json:"source,omitempty"` // +optional Schema string `json:"schema,omitempty"` - // TODO sink or broker? string or obj ref? + Broker string `json:"broker,omitempty"` } diff --git a/pkg/broker/ingress.go b/pkg/broker/ingress.go index 466d1717910..edb412bd008 100644 --- a/pkg/broker/ingress.go +++ b/pkg/broker/ingress.go @@ -1,5 +1,5 @@ /* - * Copyright 2018 The Knative Authors + * Copyright 2019 The Knative Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,12 +34,6 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" ) -const ( - allowAny = "allow_any" - allowRegisteredTypes = "allow_registered" - autoCreate = "auto_create" -) - var ( // Only allow alphanumeric, '-' or '.'. validChars = regexp.MustCompile(`[^-\.a-z0-9]+`) @@ -47,103 +41,85 @@ var ( notFound = k8serrors.NewNotFound(eventingv1alpha1.Resource("eventtype"), "") ) -type IngressPolicy interface { - AllowEvent(event *cloudevents.Event) bool -} - -type Any struct{} - -type Registered struct { - logger *zap.SugaredLogger - client client.Client - namespace string - broker string -} - -type AutoCreate struct { +type IngressPolicy struct { logger *zap.SugaredLogger client client.Client namespace string broker string + spec *eventingv1alpha1.IngressPolicySpec } -func NewIngressPolicy(logger *zap.Logger, client client.Client, namespace, broker, policy string) IngressPolicy { - return newIngressPolicy(logger.Sugar(), client, namespace, broker, policy) +func NewPolicy(logger *zap.Logger, client client.Client, spec *eventingv1alpha1.IngressPolicySpec, namespace, broker string) *IngressPolicy { + return &IngressPolicy{ + logger: logger.Sugar(), + client: client, + namespace: namespace, + broker: broker, + spec: spec, + } } -func newIngressPolicy(logger *zap.SugaredLogger, client client.Client, namespace, broker, policy string) IngressPolicy { - switch policy { - case allowRegisteredTypes: - return &Registered{ - logger: logger, - client: client, - namespace: namespace, - broker: broker, - } - case autoCreate: - return &AutoCreate{ - logger: logger, - client: client, - namespace: namespace, - broker: broker, - } - case allowAny: - return &Any{} - default: - return &Any{} +func (p *IngressPolicy) AllowEvent(ctx context.Context, event *cloudevents.Event) bool { + if p.spec.AutoAdd { + return p.autoAdd(event) } + if !p.spec.AllowAny { + return p.isRegistered(ctx, event) + } + return true } -func (p *Any) AllowEvent(event *cloudevents.Event) bool { +func (p *IngressPolicy) autoAdd(event *cloudevents.Event) bool { + // TODO do this in a working queue + go func() { + // Do not use the previous context as it seems that it can be canceled before + // this routine executes. + ctx := context.TODO() + _, err := p.getEventType(ctx, event) + if k8serrors.IsNotFound(err) { + p.logger.Infof("EventType %q not found: Adding", event.Type()) + eventType := p.makeEventType(event) + err := p.client.Create(ctx, eventType) + if err != nil { + p.logger.Errorf("Error creating EventType %q: Accept but Not Add, %v", event.Type(), err) + } + } else if err != nil { + p.logger.Errorf("Error retrieving EventType %q: Accept but Not Add, %v", event.Type(), err) + } + }() return true } -func (p *Registered) AllowEvent(event *cloudevents.Event) bool { - _, err := getEventType(p.client, event, p.namespace, p.broker) +func (p *IngressPolicy) isRegistered(ctx context.Context, event *cloudevents.Event) bool { + _, err := p.getEventType(ctx, event) if k8serrors.IsNotFound(err) { - p.logger.Warnf("EventType not found, rejecting spec.type %q, %v", event.Type(), err) + p.logger.Warnf("EventType %q not found: Reject", event.Type()) return false } else if err != nil { - p.logger.Errorf("Error retrieving EventType, rejecting spec.type %q, %v", event.Type(), err) + p.logger.Errorf("Error retrieving EventType %q: Reject, %v", event.Type(), err) return false } return true } -func (p *AutoCreate) AllowEvent(event *cloudevents.Event) bool { - _, err := getEventType(p.client, event, p.namespace, p.broker) - if k8serrors.IsNotFound(err) { - p.logger.Infof("EventType not found, creating spec.type %q", event.Type()) - eventType := makeEventType(event, p.namespace, p.broker) - err := p.client.Create(context.TODO(), eventType) - if err != nil { - p.logger.Errorf("Error creating EventType, spec.type %q, %v", event.Type(), err) - } - } else if err != nil { - p.logger.Errorf("Error retrieving EventType, spec.type %q, %v", event.Type(), err) - } - return true -} - -func getEventType(c client.Client, event *cloudevents.Event, namespace, broker string) (*eventingv1alpha1.EventType, error) { +func (p *IngressPolicy) getEventType(ctx context.Context, event *cloudevents.Event) (*eventingv1alpha1.EventType, error) { opts := &client.ListOptions{ - Namespace: namespace, + Namespace: p.namespace, // Set Raw because if we need to get more than one page, then we will put the continue token // into opts.Raw.Continue. Raw: &metav1.ListOptions{}, } - ctx := context.TODO() - for { etl := &eventingv1alpha1.EventTypeList{} - err := c.List(ctx, opts, etl) + err := p.client.List(ctx, opts, etl) if err != nil { return nil, err } for _, et := range etl.Items { - if et.Spec.Broker == broker { - // TODO what about source. + if et.Spec.Broker == p.broker { + // Matching on type and schemaURL, although this does not uniquely identify the EventType. + // If we match on source, then we will never find the EventType. if et.Spec.Type == event.Type() && et.Spec.Schema == event.SchemaURL() { return &et, nil } @@ -158,18 +134,18 @@ func getEventType(c client.Client, event *cloudevents.Event, namespace, broker s } // makeEventType generates, but does not create an EventType from the given cloudevents.Event. -func makeEventType(event *cloudevents.Event, namespace, broker string) *eventingv1alpha1.EventType { +func (p *IngressPolicy) makeEventType(event *cloudevents.Event) *eventingv1alpha1.EventType { cloudEventType := event.Type() return &eventingv1alpha1.EventType{ ObjectMeta: metav1.ObjectMeta{ GenerateName: fmt.Sprintf("%s-", toDNS1123Subdomain(cloudEventType)), - Namespace: namespace, + Namespace: p.namespace, }, Spec: eventingv1alpha1.EventTypeSpec{ Type: cloudEventType, Source: event.Source(), Schema: event.SchemaURL(), - Broker: broker, + Broker: p.broker, }, } } diff --git a/pkg/reconciler/v1alpha1/broker/resources/ingress.go b/pkg/reconciler/v1alpha1/broker/resources/ingress.go index 27c13dfe0b5..df2fd5cff23 100644 --- a/pkg/reconciler/v1alpha1/broker/resources/ingress.go +++ b/pkg/reconciler/v1alpha1/broker/resources/ingress.go @@ -18,6 +18,7 @@ package resources import ( "fmt" + "strconv" appsv1 "k8s.io/api/apps/v1" "k8s.io/apimachinery/pkg/util/intstr" @@ -76,8 +77,16 @@ func MakeIngress(args *IngressArgs) *appsv1.Deployment { Value: args.ChannelAddress, }, { - Name: "POLICY", - Value: args.Broker.Spec.IngressPolicy, + Name: "BROKER", + Value: args.Broker.Name, + }, + { + Name: "POLICY_AUTO_ADD", + Value: strconv.FormatBool(args.Broker.Spec.IngressPolicy.AutoAdd), + }, + { + Name: "POLICY_ALLOW_ANY", + Value: strconv.FormatBool(args.Broker.Spec.IngressPolicy.AllowAny), }, { Name: "NAMESPACE", From 1cf75caee968a0151b43adf20993466c9c78809a Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Fri, 22 Mar 2019 00:47:10 -0700 Subject: [PATCH 179/221] removing DeprecatedGeneration --- pkg/apis/eventing/v1alpha1/eventtype_types.go | 9 ------- .../v1alpha1/zz_generated.deepcopy.go | 25 +++++++++++++++++++ 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/pkg/apis/eventing/v1alpha1/eventtype_types.go b/pkg/apis/eventing/v1alpha1/eventtype_types.go index 6c03ac44e70..6c607e488fe 100644 --- a/pkg/apis/eventing/v1alpha1/eventtype_types.go +++ b/pkg/apis/eventing/v1alpha1/eventtype_types.go @@ -49,15 +49,6 @@ var _ runtime.Object = (*EventType)(nil) var _ webhook.GenericCRD = (*EventType)(nil) type EventTypeSpec struct { - // TODO By enabling the status subresource metadata.generation should increment - // thus making this property obsolete. - // - // We should be able to drop this property with a CRD conversion webhook - // in the future - // - // +optional - DeprecatedGeneration int64 `json:"generation,omitempty"` - Type string `json:"type,omitempty"` // +optional Source string `json:"source,omitempty"` diff --git a/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go index f11e304a574..9984c4b4ec3 100644 --- a/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go @@ -100,6 +100,15 @@ func (in *BrokerSpec) DeepCopyInto(out *BrokerSpec) { (*in).DeepCopyInto(*out) } } + if in.IngressPolicy != nil { + in, out := &in.IngressPolicy, &out.IngressPolicy + if *in == nil { + *out = nil + } else { + *out = new(IngressPolicySpec) + **out = **in + } + } return } @@ -456,6 +465,22 @@ func (in *EventTypeStatus) DeepCopy() *EventTypeStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IngressPolicySpec) DeepCopyInto(out *IngressPolicySpec) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IngressPolicySpec. +func (in *IngressPolicySpec) DeepCopy() *IngressPolicySpec { + if in == nil { + return nil + } + out := new(IngressPolicySpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ReplyStrategy) DeepCopyInto(out *ReplyStrategy) { *out = *in From 32383a733a6032a0f7a007aee3d60fc4a7d9e4b7 Mon Sep 17 00:00:00 2001 From: nachocano Date: Fri, 22 Mar 2019 11:45:48 -0700 Subject: [PATCH 180/221] Adding README --- docs/registry/README.md | 169 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 169 insertions(+) create mode 100644 docs/registry/README.md diff --git a/docs/registry/README.md b/docs/registry/README.md new file mode 100644 index 00000000000..0bec11eb929 --- /dev/null +++ b/docs/registry/README.md @@ -0,0 +1,169 @@ +# Registry Proposal + +## Objective + +Design an initial version of the Registry that can support discoverability of +the different event types that can be consumed from the eventing mesh. + +## Requirements + +Our design revolves around the following core requirements: + +1. We should have a Registry per namespace to enforce isolation. +2. The Registry should contain only the event types that can be consumed from +the eventing mesh. +3. The event types stored in the Registry should contain all the required information +for a consumer to create a trigger without resorting to some other OOB mechanism. + +## Design Ideas + +### EventType CRD + +We propose having a namespaced EventType CRD. Here is an example of how a CR would look like: + +```yaml +apiVersion: eventing.knative.dev/v1alpha1 +kind: EventType +metadata: + name: repopush +spec: + type: repo:push + source: user/repo + schema: http://schemas/repo/push + broker: default +``` + + +- The `name` of the EventType is advisory, non-authoritative. Given that Cloud Event types can +contain characters that may not comply with Kubernetes naming conventions, we will (slightly) +modify those names to make them K8s-compliant, whenever we need to generate them. + +- `type` is authoritative. This refers to the Cloud Event type as it enters into the eventing mesh. + +- `source`: an identifier of where we receive the event from. This might not necessarily be the Cloud Event source +attribute. + +- `schema` is a URI with the EventType schema. It may be a JSON schema, a protobuf schema, etc. It is optional. + +- `broker` refers to the Broker that can provide the EventType. + +### EventType Instantiation + +We foresee the following ways of populating the Registry: + +**1. Event Source CR installation** + +Upon installation of an Event Source CR, the source will register its EventTypes. + +Example: + +``` +apiVersion: sources.eventing.knative.dev/v1alpha1 +kind: GitHubSource +metadata: + name: github-source-sample +spec: + eventTypes: + - push + - pull_request + ownerAndRepository: linda/eventing + accessToken: + secretKeyRef: + name: github-secret + key: accessToken + secretToken: + secretKeyRef: + name: github-secret + key: secretToken + sink: + apiVersion: eventing.knative.dev/v1alpha1 + kind: Broker + name: default + +``` + +By applying this file, two EventTypes will be registered, with types `push` and `pull_request`, +source `linda/eventing`, for the `default` Broker in the `default` namespace. + +**2. Manual User Registration** + +A user manually `kubectl applies` an EventType CR. + +Example: + +```yaml +apiVersion: eventing.knative.dev/v1alpha1 +kind: EventType +metadata: + name: repofork +spec: + type: repo:fork + source: user/repo + broker: dev +``` + +This would register the EventType named `repofork` with type `repo:fork`, source `user/repo` in the `dev` +Broker of the `default` namespace. + + +**3. Broker Auto Registration Policy** + +Upon arrival of a non-registered EventType to a Broker ingress, and in case the Broker +ingress policy allows auto-registration of EventTypes, the Broker will create the EventType. + +Example: + +Set up a Broker with `autoAdd` enabled. + +``` +apiVersion: eventing.knative.dev/v1alpha1 +kind: Broker +metadata: + name: auto-add-demo +spec: + ingressPolicy: + autoAdd: true +``` + +Now if someone emits a non-registered event (e.g., `dev.knative.foo.bar`) +into the Broker `auto-add-demo`, an EventType will be created upon the event arrival. +Note that the Broker's address is well-known, it will always be +`-broker..svc.`. In this case case, it is +`auto-add-demo-broker.default.svc.cluster.local`. + +We can send the event manually. While SSHed into a `Pod` with the Istio sidecar, run: + +```shell +curl -v "http://auto-add-demo-broker.default.svc.cluster.local/" \ + -X POST \ + -H "X-B3-Flags: 1" \ + -H "CE-CloudEventsVersion: 0.1" \ + -H "CE-EventType: dev.knative.foo.bar" \ + -H "CE-EventTime: 2018-04-05T03:56:24Z" \ + -H "CE-EventID: 45a8b444-3213-4758-be3f-540bf93f85ff" \ + -H "CE-Source: dev.knative.example" \ + -H 'Content-Type: application/json' \ + -d '{ "much": "wow" }' +``` + +The Broker `auto-add-demo` will then create the EventType with type `dev.knative.foo.bar` in the Registry. + +## Use Case: Discoverability + +*As an Event Consumer I want to discover the different event types that I can consume from a +particular broker without resorting to any OOB mechanism.* + +By adding the spec.* fields of EventType as custom columns in the CRD we can fulfill this use case. + + +`$ kubectl get eventtypes -n default` + + +NAME | TYPE | SOURCE | SCHEMA | BROKER | READY | REASON +--- | --- | --- | --- | --- | --- | --- +dev.knative.foo.bar-55wcn | dev.knative.foo.bar | dev.knative.example | | auto-add-demo | True | | +repofork | repo:fork | user/repo | | dev | False | BrokerIsNotReady | +repopush | repo:push | user/repo | http://schemas/repo/push | default | True | | +dev.knative.source.github.push-34cnb | dev.knative.source.github.push | linda/eventing | | default | True | | +dev.knative.source.github.pullrequest-86jhv | dev.knative.source.github.pull_request | linda/eventing | | default | True | | + From 52abb770340c1814980973ac1e06a43275650249 Mon Sep 17 00:00:00 2001 From: nachocano Date: Fri, 22 Mar 2019 11:47:48 -0700 Subject: [PATCH 181/221] yaml --- docs/registry/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/registry/README.md b/docs/registry/README.md index 0bec11eb929..ddb0b723b8e 100644 --- a/docs/registry/README.md +++ b/docs/registry/README.md @@ -57,7 +57,7 @@ Upon installation of an Event Source CR, the source will register its EventTypes Example: -``` +```yaml apiVersion: sources.eventing.knative.dev/v1alpha1 kind: GitHubSource metadata: @@ -115,7 +115,7 @@ Example: Set up a Broker with `autoAdd` enabled. -``` +```yaml apiVersion: eventing.knative.dev/v1alpha1 kind: Broker metadata: From c86581b2fefa5e7dfa828d4fa04aa32827f010f8 Mon Sep 17 00:00:00 2001 From: nachocano Date: Fri, 22 Mar 2019 13:47:11 -0700 Subject: [PATCH 182/221] updating readme --- docs/registry/README.md | 62 ++++++++++++++++++++++++++++------------- 1 file changed, 43 insertions(+), 19 deletions(-) diff --git a/docs/registry/README.md b/docs/registry/README.md index ddb0b723b8e..12516918fb8 100644 --- a/docs/registry/README.md +++ b/docs/registry/README.md @@ -2,7 +2,7 @@ ## Objective -Design an initial version of the Registry that can support discoverability of +Design an **initial** version of the Registry that can support discoverability of the different event types that can be consumed from the eventing mesh. ## Requirements @@ -10,10 +10,10 @@ the different event types that can be consumed from the eventing mesh. Our design revolves around the following core requirements: 1. We should have a Registry per namespace to enforce isolation. -2. The Registry should contain only the event types that can be consumed from -the eventing mesh. +2. The Registry should contain the event types that can be consumed from +the eventing mesh. If an event type is not ready for consumption, we should explicitly indicate so. 3. The event types stored in the Registry should contain all the required information -for a consumer to create a trigger without resorting to some other OOB mechanism. +for a consumer to create a Trigger without resorting to some other OOB mechanism. ## Design Ideas @@ -28,8 +28,8 @@ metadata: name: repopush spec: type: repo:push - source: user/repo - schema: http://schemas/repo/push + source: my-user/my-repo + schema: http://schemas/bitbucket/repo/push broker: default ``` @@ -62,11 +62,12 @@ apiVersion: sources.eventing.knative.dev/v1alpha1 kind: GitHubSource metadata: name: github-source-sample + namespace: default spec: eventTypes: - push - pull_request - ownerAndRepository: linda/eventing + ownerAndRepository: my-other-user/my-other-repo accessToken: secretKeyRef: name: github-secret @@ -83,7 +84,7 @@ spec: ``` By applying this file, two EventTypes will be registered, with types `push` and `pull_request`, -source `linda/eventing`, for the `default` Broker in the `default` namespace. +source `my-other-user/my-other-repo`, for the `default` Broker in the `default` namespace. **2. Manual User Registration** @@ -96,14 +97,15 @@ apiVersion: eventing.knative.dev/v1alpha1 kind: EventType metadata: name: repofork + namespace: default spec: type: repo:fork - source: user/repo + source: my-other-user/my-other-repo broker: dev ``` -This would register the EventType named `repofork` with type `repo:fork`, source `user/repo` in the `dev` -Broker of the `default` namespace. +This would register the EventType named `repofork` with type `repo:fork`, source `my-other-user/my-other-repo` +in the `dev` Broker of the `default` namespace. **3. Broker Auto Registration Policy** @@ -148,13 +150,15 @@ curl -v "http://auto-add-demo-broker.default.svc.cluster.local/" \ The Broker `auto-add-demo` will then create the EventType with type `dev.knative.foo.bar` in the Registry. -## Use Case: Discoverability +## Discoverability Use Case -*As an Event Consumer I want to discover the different event types that I can consume from a -particular broker without resorting to any OOB mechanism.* +By adding the spec.* fields of EventType as custom columns in the CRD we can fulfill the discoverability +use case: -By adding the spec.* fields of EventType as custom columns in the CRD we can fulfill this use case. +*As an Event Consumer I want to be able to discover the different event types that I can consume +from the different Brokers, without resorting to any OOB mechanism.* +First, Event Consumers will list the EventTypes registered in the system `$ kubectl get eventtypes -n default` @@ -162,8 +166,28 @@ By adding the spec.* fields of EventType as custom columns in the CRD we can ful NAME | TYPE | SOURCE | SCHEMA | BROKER | READY | REASON --- | --- | --- | --- | --- | --- | --- dev.knative.foo.bar-55wcn | dev.knative.foo.bar | dev.knative.example | | auto-add-demo | True | | -repofork | repo:fork | user/repo | | dev | False | BrokerIsNotReady | -repopush | repo:push | user/repo | http://schemas/repo/push | default | True | | -dev.knative.source.github.push-34cnb | dev.knative.source.github.push | linda/eventing | | default | True | | -dev.knative.source.github.pullrequest-86jhv | dev.knative.source.github.pull_request | linda/eventing | | default | True | | +repofork | repo:fork | my-other-user/my-other-repo | | dev | False | BrokerIsNotReady | +repopush | repo:push | my-other-user/my-other-repo | http://schemas/bitbucket/repo/push | default | True | | +dev.knative.source.github.push-34cnb | dev.knative.source.github.push | my-user/my-repo | | default | True | | +dev.knative.source.github.pullrequest-86jhv | dev.knative.source.github.pull_request | my-user/my-repo | | default | True | | + +Then, they will be able to *easily* create the appropriate Trigger(s) + + +```yaml +apiVersion: eventing.knative.dev/v1alpha1 +kind: Trigger +metadata: + name: my-service-trigger + namespace: default +spec: + filter: + sourceAndType: + type: dev.knative.source.github.push + subscriber: + ref: + apiVersion: serving.knative.dev/v1alpha1 + kind: Service + name: my-service +``` From c066a102c03edb611dfab049b5615345411236a5 Mon Sep 17 00:00:00 2001 From: nachocano Date: Fri, 22 Mar 2019 13:50:43 -0700 Subject: [PATCH 183/221] updating trigger --- docs/registry/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/registry/README.md b/docs/registry/README.md index 12516918fb8..a19ad7db0be 100644 --- a/docs/registry/README.md +++ b/docs/registry/README.md @@ -184,7 +184,8 @@ metadata: spec: filter: sourceAndType: - type: dev.knative.source.github.push + type: dev.knative.foo.bar + source: dev.knative.example subscriber: ref: apiVersion: serving.knative.dev/v1alpha1 From 7782715dcf576cc41068a406a96a695f10fdf0dc Mon Sep 17 00:00:00 2001 From: nachocano Date: Fri, 22 Mar 2019 15:33:58 -0700 Subject: [PATCH 184/221] all fields immutable in eventType. this makes our life easier when reconciling them from sources. --- pkg/apis/eventing/v1alpha1/eventtype_validation.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/pkg/apis/eventing/v1alpha1/eventtype_validation.go b/pkg/apis/eventing/v1alpha1/eventtype_validation.go index 9b5303538f7..0083aa7633d 100644 --- a/pkg/apis/eventing/v1alpha1/eventtype_validation.go +++ b/pkg/apis/eventing/v1alpha1/eventtype_validation.go @@ -20,7 +20,6 @@ import ( "context" "github.com/google/go-cmp/cmp" - "github.com/google/go-cmp/cmp/cmpopts" "github.com/knative/pkg/apis" ) @@ -51,9 +50,8 @@ func (et *EventType) CheckImmutableFields(ctx context.Context, og apis.Immutable return &apis.FieldError{Message: "The provided original was not an EventType"} } - // Schema and Broker mutable. - ignoreArguments := cmpopts.IgnoreFields(EventTypeSpec{}, "Schema", "Broker") - if diff := cmp.Diff(original.Spec, et.Spec, ignoreArguments); diff != "" { + // All fields immutable, otherwise it creates a problem when reconciling from sources. + if diff := cmp.Diff(original.Spec, et.Spec); diff != "" { return &apis.FieldError{ Message: "Immutable fields changed (-old +new)", Paths: []string{"spec"}, From 2a49a81ae82e8896ffe920d53f42dbeb814d2ebf Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Mon, 25 Mar 2019 09:07:23 -0700 Subject: [PATCH 185/221] adding UTs --- cmd/broker/ingress/main.go | 4 +- .../v1alpha1/eventtype_defaults_test.go | 83 ++++++ .../eventing/v1alpha1/eventtype_types_test.go | 247 ++++++++++++++++ .../eventing/v1alpha1/eventtype_validation.go | 2 +- .../v1alpha1/eventtype_validation_test.go | 238 +++++++++++++++ pkg/broker/ingress.go | 32 +- pkg/broker/ingress_test.go | 213 +++++++++++++ pkg/reconciler/v1alpha1/broker/broker_test.go | 4 + .../v1alpha1/eventtype/eventtype.go | 5 +- .../v1alpha1/eventtype/eventtype_test.go | 279 ++++++++++++++++++ .../v1alpha1/namespace/namespace_test.go | 32 +- 11 files changed, 1113 insertions(+), 26 deletions(-) create mode 100644 pkg/apis/eventing/v1alpha1/eventtype_defaults_test.go create mode 100644 pkg/apis/eventing/v1alpha1/eventtype_types_test.go create mode 100644 pkg/apis/eventing/v1alpha1/eventtype_validation_test.go create mode 100644 pkg/broker/ingress_test.go create mode 100644 pkg/reconciler/v1alpha1/eventtype/eventtype_test.go diff --git a/cmd/broker/ingress/main.go b/cmd/broker/ingress/main.go index bbb0c3ad478..035d575ec08 100644 --- a/cmd/broker/ingress/main.go +++ b/cmd/broker/ingress/main.go @@ -81,7 +81,7 @@ func main() { } brokerName := getRequiredEnv("BROKER") - ingressPolicy := broker.NewPolicy(logger, client, policySpec, namespace, brokerName) + ingressPolicy := broker.NewPolicy(logger, client, policySpec, namespace, brokerName, true) // Create an event handler. ceHTTP, err := cehttp.New(cehttp.WithBinaryEncoding(), cehttp.WithPort(defaultPort)) @@ -189,7 +189,7 @@ func (h *handler) serveHTTP(ctx context.Context, event cloudevents.Event, resp * } func (h *handler) allowEvent(ctx context.Context, event cloudevents.Event) bool { - return h.ingressPolicy.AllowEvent(ctx, &event) + return h.ingressPolicy.AllowEvent(ctx, event) } func (h *handler) sendEvent(ctx context.Context, tctx cehttp.TransportContext, event cloudevents.Event) error { diff --git a/pkg/apis/eventing/v1alpha1/eventtype_defaults_test.go b/pkg/apis/eventing/v1alpha1/eventtype_defaults_test.go new file mode 100644 index 00000000000..6ac447be495 --- /dev/null +++ b/pkg/apis/eventing/v1alpha1/eventtype_defaults_test.go @@ -0,0 +1,83 @@ +/* +Copyright 2019 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + "context" + "testing" + + "github.com/google/go-cmp/cmp" +) + +func TestEventTypeDefaults(t *testing.T) { + 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: "test-source", + Broker: "", + Schema: "test-schema", + }, + }, + expected: EventType{ + Spec: EventTypeSpec{ + Type: "test-type", + Source: "test-source", + Broker: "default", + Schema: "test-schema", + }, + }, + }, + "broker not set": { + initial: EventType{ + Spec: EventTypeSpec{ + Type: "test-type", + Source: "test-source", + Schema: "test-schema", + }, + }, + expected: EventType{ + Spec: EventTypeSpec{ + Type: "test-type", + Source: "test-source", + Broker: "default", + Schema: "test-schema", + }, + }, + }, + } + 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/v1alpha1/eventtype_types_test.go b/pkg/apis/eventing/v1alpha1/eventtype_types_test.go new file mode 100644 index 00000000000..d88c3fcb308 --- /dev/null +++ b/pkg/apis/eventing/v1alpha1/eventtype_types_test.go @@ -0,0 +1,247 @@ +/* +Copyright 2019 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" + corev1 "k8s.io/api/core/v1" +) + +var ( + trueValue = true + falseValue = false +) + +var ( + eventTypeConditionReady = duckv1alpha1.Condition{ + Type: EventTypeConditionReady, + Status: corev1.ConditionTrue, + } + + eventTypeConditionBrokerExists = duckv1alpha1.Condition{ + Type: EventTypeConditionBrokerExists, + Status: corev1.ConditionTrue, + } + + eventTypeConditionBrokerReady = duckv1alpha1.Condition{ + Type: EventTypeConditionBrokerReady, + Status: corev1.ConditionTrue, + } +) + +func TestEventTypeGetCondition(t *testing.T) { + tests := []struct { + name string + ets *EventTypeStatus + condQuery duckv1alpha1.ConditionType + want *duckv1alpha1.Condition + }{{ + name: "single condition", + ets: &EventTypeStatus{ + Status: duckv1alpha1.Status{ + Conditions: []duckv1alpha1.Condition{ + eventTypeConditionReady, + }, + }, + }, + condQuery: duckv1alpha1.ConditionReady, + want: &eventTypeConditionReady, + }, { + name: "broker exists condition", + ets: &EventTypeStatus{ + Status: duckv1alpha1.Status{ + Conditions: []duckv1alpha1.Condition{ + eventTypeConditionBrokerExists, + }, + }, + }, + condQuery: EventTypeConditionBrokerExists, + want: &eventTypeConditionBrokerExists, + }, { + name: "multiple conditions, condition true", + ets: &EventTypeStatus{ + Status: duckv1alpha1.Status{ + Conditions: []duckv1alpha1.Condition{ + eventTypeConditionBrokerExists, + eventTypeConditionBrokerReady, + }, + }, + }, + condQuery: EventTypeConditionBrokerReady, + want: &eventTypeConditionBrokerReady, + }, { + name: "unknown condition", + ets: &EventTypeStatus{ + Status: duckv1alpha1.Status{ + Conditions: []duckv1alpha1.Condition{ + eventTypeConditionBrokerReady, + eventTypeConditionReady, + }, + }, + }, + condQuery: duckv1alpha1.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: duckv1alpha1.Status{ + Conditions: []duckv1alpha1.Condition{{ + Type: EventTypeConditionBrokerExists, + Status: corev1.ConditionUnknown, + }, { + Type: EventTypeConditionBrokerReady, + Status: corev1.ConditionUnknown, + }, { + Type: EventTypeConditionReady, + Status: corev1.ConditionUnknown, + }, + }, + }, + }, + }, { + name: "one false", + ets: &EventTypeStatus{ + Status: duckv1alpha1.Status{ + Conditions: []duckv1alpha1.Condition{{ + Type: EventTypeConditionBrokerExists, + Status: corev1.ConditionFalse, + }}, + }, + }, + want: &EventTypeStatus{ + Status: duckv1alpha1.Status{ + Conditions: []duckv1alpha1.Condition{{ + Type: EventTypeConditionBrokerExists, + Status: corev1.ConditionFalse, + }, { + Type: EventTypeConditionBrokerReady, + Status: corev1.ConditionUnknown, + }, { + Type: EventTypeConditionReady, + Status: corev1.ConditionUnknown, + }}, + }, + }, + }, { + name: "one true", + ets: &EventTypeStatus{ + Status: duckv1alpha1.Status{ + Conditions: []duckv1alpha1.Condition{{ + Type: EventTypeConditionBrokerReady, + Status: corev1.ConditionTrue, + }}, + }, + }, + want: &EventTypeStatus{ + Status: duckv1alpha1.Status{ + Conditions: []duckv1alpha1.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 TestEventTypeIsReady(t *testing.T) { + tests := []struct { + name string + markBrokerExists *bool + markBrokerReady *bool + wantReady bool + }{{ + name: "all happy", + markBrokerExists: &trueValue, + markBrokerReady: &trueValue, + wantReady: true, + }, { + name: "broker exist sad", + markBrokerExists: &falseValue, + markBrokerReady: &trueValue, + wantReady: false, + }, { + name: "broker ready sad", + markBrokerExists: &trueValue, + markBrokerReady: &falseValue, + wantReady: false, + }, { + name: "all sad", + markBrokerExists: &falseValue, + markBrokerReady: &falseValue, + wantReady: false, + }} + 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.markBrokerReady != nil { + if *test.markBrokerReady { + ets.MarkBrokerReady() + } else { + ets.MarkBrokerNotReady() + } + } + + got := ets.IsReady() + if test.wantReady != got { + t.Errorf("unexpected readiness: want %v, got %v", test.wantReady, got) + } + }) + } +} diff --git a/pkg/apis/eventing/v1alpha1/eventtype_validation.go b/pkg/apis/eventing/v1alpha1/eventtype_validation.go index 0083aa7633d..f43c32fea23 100644 --- a/pkg/apis/eventing/v1alpha1/eventtype_validation.go +++ b/pkg/apis/eventing/v1alpha1/eventtype_validation.go @@ -50,7 +50,7 @@ func (et *EventType) CheckImmutableFields(ctx context.Context, og apis.Immutable return &apis.FieldError{Message: "The provided original was not an EventType"} } - // All fields immutable, otherwise it creates a problem when reconciling from sources. + // All fields immutable. if diff := cmp.Diff(original.Spec, et.Spec); diff != "" { return &apis.FieldError{ Message: "Immutable fields changed (-old +new)", diff --git a/pkg/apis/eventing/v1alpha1/eventtype_validation_test.go b/pkg/apis/eventing/v1alpha1/eventtype_validation_test.go new file mode 100644 index 00000000000..eaaa897ef14 --- /dev/null +++ b/pkg/apis/eventing/v1alpha1/eventtype_validation_test.go @@ -0,0 +1,238 @@ +/* +Copyright 2019 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + "context" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/knative/pkg/apis" +) + +func TestEventTypeValidation(t *testing.T) { + name := "invalid type and broker" + broker := &EventType{Spec: EventTypeSpec{}} + + want := &apis.FieldError{ + Paths: []string{"spec.type", "spec.broker"}, + Message: "missing field(s)", + } + + t.Run(name, func(t *testing.T) { + got := broker.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) { + tests := []struct { + name string + ets *EventTypeSpec + want *apis.FieldError + }{{ + name: "invalid eventtype spec", + ets: &EventTypeSpec{}, + want: func() *apis.FieldError { + fe := apis.ErrMissingField("type", "broker") + return fe + }(), + }, { + name: "invalid eventtype type", + ets: &EventTypeSpec{ + Broker: "test-broker", + }, + want: func() *apis.FieldError { + fe := apis.ErrMissingField("type") + return fe + }(), + }, { + name: "invalid eventtype broker", + ets: &EventTypeSpec{ + Type: "test-type", + }, + want: func() *apis.FieldError { + fe := apis.ErrMissingField("broker") + return fe + }(), + }, + } + + 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) { + tests := []struct { + name string + current apis.Immutable + original apis.Immutable + want *apis.FieldError + }{{ + name: "good (no change)", + current: &EventType{ + Spec: EventTypeSpec{ + Type: "test-type", + Source: "test-source", + Broker: "test-broker", + Schema: "test-schema", + }, + }, + original: &EventType{ + Spec: EventTypeSpec{ + Type: "test-type", + Source: "test-source", + Broker: "test-broker", + Schema: "test-schema", + }, + }, + want: nil, + }, { + name: "new nil is ok", + current: &EventType{ + Spec: EventTypeSpec{ + Type: "test-type", + Source: "test-source", + Broker: "test-broker", + Schema: "test-schema", + }, + }, + original: nil, + want: nil, + }, { + name: "invalid type", + current: &EventType{ + Spec: EventTypeSpec{ + Type: "test-type", + Broker: "test-broker", + }, + }, + original: &Trigger{}, + want: &apis.FieldError{ + Message: "The provided original was not an EventType", + }, + }, { + name: "bad (broker change)", + current: &EventType{ + Spec: EventTypeSpec{ + Type: "test-type", + Broker: "test-broker", + }, + }, + original: &EventType{ + Spec: EventTypeSpec{ + Type: "test-type", + Broker: "original-broker", + }, + }, + want: &apis.FieldError{ + Message: "Immutable fields changed (-old +new)", + Paths: []string{"spec"}, + Details: `{v1alpha1.EventTypeSpec}.Broker: + -: "original-broker" + +: "test-broker" +`, + }, + }, { + name: "bad (type change)", + current: &EventType{ + Spec: EventTypeSpec{ + Type: "test-type", + Broker: "test-broker", + }, + }, + original: &EventType{ + Spec: EventTypeSpec{ + Type: "original-type", + Broker: "test-broker", + }, + }, + want: &apis.FieldError{ + Message: "Immutable fields changed (-old +new)", + Paths: []string{"spec"}, + Details: `{v1alpha1.EventTypeSpec}.Type: + -: "original-type" + +: "test-type" +`, + }, + }, { + name: "bad (schema change)", + current: &EventType{ + Spec: EventTypeSpec{ + Type: "test-type", + Broker: "test-broker", + Schema: "test-schema", + }, + }, + original: &EventType{ + Spec: EventTypeSpec{ + Type: "test-type", + Broker: "test-broker", + Schema: "original-schema", + }, + }, + want: &apis.FieldError{ + Message: "Immutable fields changed (-old +new)", + Paths: []string{"spec"}, + Details: `{v1alpha1.EventTypeSpec}.Schema: + -: "original-schema" + +: "test-schema" +`, + }, + }, { + name: "bad (source change)", + current: &EventType{ + Spec: EventTypeSpec{ + Type: "test-type", + Broker: "test-broker", + Source: "test-source", + }, + }, + original: &EventType{ + Spec: EventTypeSpec{ + Type: "test-type", + Broker: "test-broker", + Source: "original-source", + }, + }, + want: &apis.FieldError{ + Message: "Immutable fields changed (-old +new)", + Paths: []string{"spec"}, + Details: `{v1alpha1.EventTypeSpec}.Source: + -: "original-source" + +: "test-source" +`, + }, + }} + + 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/broker/ingress.go b/pkg/broker/ingress.go index edb412bd008..a18ac2e7fb9 100644 --- a/pkg/broker/ingress.go +++ b/pkg/broker/ingress.go @@ -47,21 +47,23 @@ type IngressPolicy struct { namespace string broker string spec *eventingv1alpha1.IngressPolicySpec + async bool } -func NewPolicy(logger *zap.Logger, client client.Client, spec *eventingv1alpha1.IngressPolicySpec, namespace, broker string) *IngressPolicy { +func NewPolicy(logger *zap.Logger, client client.Client, spec *eventingv1alpha1.IngressPolicySpec, namespace, broker string, async bool) *IngressPolicy { return &IngressPolicy{ logger: logger.Sugar(), client: client, namespace: namespace, broker: broker, spec: spec, + async: async, } } -func (p *IngressPolicy) AllowEvent(ctx context.Context, event *cloudevents.Event) bool { +func (p *IngressPolicy) AllowEvent(ctx context.Context, event cloudevents.Event) bool { if p.spec.AutoAdd { - return p.autoAdd(event) + return p.autoAdd(ctx, event) } if !p.spec.AllowAny { return p.isRegistered(ctx, event) @@ -69,12 +71,8 @@ func (p *IngressPolicy) AllowEvent(ctx context.Context, event *cloudevents.Event return true } -func (p *IngressPolicy) autoAdd(event *cloudevents.Event) bool { - // TODO do this in a working queue - go func() { - // Do not use the previous context as it seems that it can be canceled before - // this routine executes. - ctx := context.TODO() +func (p *IngressPolicy) autoAdd(ctx context.Context, event cloudevents.Event) bool { + addFunc := func(ctx context.Context) { _, err := p.getEventType(ctx, event) if k8serrors.IsNotFound(err) { p.logger.Infof("EventType %q not found: Adding", event.Type()) @@ -86,11 +84,19 @@ func (p *IngressPolicy) autoAdd(event *cloudevents.Event) bool { } else if err != nil { p.logger.Errorf("Error retrieving EventType %q: Accept but Not Add, %v", event.Type(), err) } - }() + } + if p.async { + // TODO do this in a working queue + // Do not use the previous context as it seems that it can be canceled before + // this routine executes. + go addFunc(context.TODO()) + } else { + addFunc(ctx) + } return true } -func (p *IngressPolicy) isRegistered(ctx context.Context, event *cloudevents.Event) bool { +func (p *IngressPolicy) isRegistered(ctx context.Context, event cloudevents.Event) bool { _, err := p.getEventType(ctx, event) if k8serrors.IsNotFound(err) { p.logger.Warnf("EventType %q not found: Reject", event.Type()) @@ -102,7 +108,7 @@ func (p *IngressPolicy) isRegistered(ctx context.Context, event *cloudevents.Eve return true } -func (p *IngressPolicy) getEventType(ctx context.Context, event *cloudevents.Event) (*eventingv1alpha1.EventType, error) { +func (p *IngressPolicy) getEventType(ctx context.Context, event cloudevents.Event) (*eventingv1alpha1.EventType, error) { opts := &client.ListOptions{ Namespace: p.namespace, // Set Raw because if we need to get more than one page, then we will put the continue token @@ -134,7 +140,7 @@ func (p *IngressPolicy) getEventType(ctx context.Context, event *cloudevents.Eve } // makeEventType generates, but does not create an EventType from the given cloudevents.Event. -func (p *IngressPolicy) makeEventType(event *cloudevents.Event) *eventingv1alpha1.EventType { +func (p *IngressPolicy) makeEventType(event cloudevents.Event) *eventingv1alpha1.EventType { cloudEventType := event.Type() return &eventingv1alpha1.EventType{ ObjectMeta: metav1.ObjectMeta{ diff --git a/pkg/broker/ingress_test.go b/pkg/broker/ingress_test.go new file mode 100644 index 00000000000..3bf0337e3ab --- /dev/null +++ b/pkg/broker/ingress_test.go @@ -0,0 +1,213 @@ +/* + * Copyright 2019 The Knative Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 broker + +import ( + "context" + "errors" + "fmt" + "net/url" + "testing" + + "k8s.io/apimachinery/pkg/api/equality" + + "sigs.k8s.io/controller-runtime/pkg/client" + + "go.uber.org/zap" + + "github.com/cloudevents/sdk-go/pkg/cloudevents" + "github.com/cloudevents/sdk-go/pkg/cloudevents/types" + eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" + controllertesting "github.com/knative/eventing/pkg/reconciler/testing" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/kubernetes/scheme" + "sigs.k8s.io/controller-runtime/pkg/client/fake" +) + +const ( + broker = "test-broker" + namespace = "test-namespace" + testType = "test-type" + otherType = "other-test-type" + testSource = "/test-source" +) + +func init() { + // Add types to scheme. + _ = eventingv1alpha1.AddToScheme(scheme.Scheme) +} + +func TestIngress(t *testing.T) { + testCases := map[string]struct { + eventTypes []*eventingv1alpha1.EventType + mocks controllertesting.Mocks + event cloudevents.Event + policySpec *eventingv1alpha1.IngressPolicySpec + want bool + // TODO add wantPresent to check creation of an EventType + }{ + "allow any, accept": { + policySpec: &eventingv1alpha1.IngressPolicySpec{ + AllowAny: true, + }, + want: true, + }, + "allow registered, error listing types, reject": { + policySpec: &eventingv1alpha1.IngressPolicySpec{ + AllowAny: false, + }, + event: makeCloudEvent(), + mocks: controllertesting.Mocks{ + MockLists: []controllertesting.MockList{ + func(_ client.Client, _ context.Context, _ *client.ListOptions, _ runtime.Object) (controllertesting.MockHandled, error) { + return controllertesting.Handled, errors.New("error listing types") + }, + }, + }, + want: false, + }, + "allow registered, event not found, reject": { + policySpec: &eventingv1alpha1.IngressPolicySpec{ + AllowAny: false, + }, + event: makeCloudEvent(), + eventTypes: []*eventingv1alpha1.EventType{ + makeDifferentEventType(), + }, + want: false, + }, + "allow registered, event registered, accept": { + policySpec: &eventingv1alpha1.IngressPolicySpec{ + AllowAny: false, + }, + event: makeCloudEvent(), + eventTypes: []*eventingv1alpha1.EventType{ + makeEventType(), + }, + want: true, + }, + "auto add, error listing types, accept": { + policySpec: &eventingv1alpha1.IngressPolicySpec{ + AutoAdd: true, + }, + event: makeCloudEvent(), + mocks: controllertesting.Mocks{ + MockLists: []controllertesting.MockList{ + func(_ client.Client, _ context.Context, _ *client.ListOptions, _ runtime.Object) (controllertesting.MockHandled, error) { + return controllertesting.Handled, errors.New("error listing types") + }, + }, + }, + want: true, + }, + "auto add, error creating type, accept": { + policySpec: &eventingv1alpha1.IngressPolicySpec{ + AutoAdd: true, + }, + event: makeCloudEvent(), + mocks: controllertesting.Mocks{ + MockCreates: []controllertesting.MockCreate{ + func(_ client.Client, _ context.Context, obj runtime.Object) (controllertesting.MockHandled, error) { + return controllertesting.Handled, errors.New("error creating type") + }, + }, + }, + want: true, + }, + "auto add, created type, accept": { + policySpec: &eventingv1alpha1.IngressPolicySpec{ + AutoAdd: true, + }, + event: makeCloudEvent(), + mocks: controllertesting.Mocks{ + MockCreates: []controllertesting.MockCreate{ + func(_ client.Client, _ context.Context, obj runtime.Object) (controllertesting.MockHandled, error) { + et := obj.(*eventingv1alpha1.EventType) + expected := makeEventType().Spec + if !equality.Semantic.DeepDerivative(et.Spec, expected) { + return controllertesting.Handled, errors.New("error creating type") + } + return controllertesting.Unhandled, nil + }, + }, + }, + want: true, + }, + } + for n, tc := range testCases { + t.Run(n, func(t *testing.T) { + + ctx := context.TODO() + objs := make([]runtime.Object, 0, len(tc.eventTypes)) + for _, et := range tc.eventTypes { + objs = append(objs, et) + } + + c := newClient(objs, tc.mocks) + policy := NewPolicy(zap.NewNop(), c, tc.policySpec, namespace, broker, false) + + got := policy.AllowEvent(ctx, tc.event) + + if tc.want != got { + t.Errorf("want %t, got %t", tc.want, got) + } + + }) + } +} + +func newClient(initial []runtime.Object, mocks controllertesting.Mocks) *controllertesting.MockClient { + innerClient := fake.NewFakeClient(initial...) + return controllertesting.NewMockClient(innerClient, mocks) +} + +func makeCloudEvent() cloudevents.Event { + return cloudevents.Event{ + Context: cloudevents.EventContextV02{ + Type: testType, + Source: types.URLRef{ + URL: url.URL{ + Path: testSource, + }, + }, + ContentType: cloudevents.StringOfApplicationJSON(), + }, + } +} + +func makeEventTypeFor(eventType string) *eventingv1alpha1.EventType { + return &eventingv1alpha1.EventType{ + ObjectMeta: metav1.ObjectMeta{ + GenerateName: fmt.Sprintf("%s-", eventType), + Namespace: namespace, + }, + Spec: eventingv1alpha1.EventTypeSpec{ + Type: eventType, + Broker: broker, + Source: testSource, + }, + } +} + +func makeEventType() *eventingv1alpha1.EventType { + return makeEventTypeFor(testType) +} + +func makeDifferentEventType() *eventingv1alpha1.EventType { + return makeEventTypeFor(otherType) +} diff --git a/pkg/reconciler/v1alpha1/broker/broker_test.go b/pkg/reconciler/v1alpha1/broker/broker_test.go index c6e7a9799b5..4a1b9f4ff8f 100644 --- a/pkg/reconciler/v1alpha1/broker/broker_test.go +++ b/pkg/reconciler/v1alpha1/broker/broker_test.go @@ -859,6 +859,10 @@ func makeBroker() *v1alpha1.Broker { ChannelTemplate: &v1alpha1.ChannelSpec{ Provisioner: channelProvisioner, }, + IngressPolicy: &v1alpha1.IngressPolicySpec{ + AllowAny: true, + AutoAdd: false, + }, }, } } diff --git a/pkg/reconciler/v1alpha1/eventtype/eventtype.go b/pkg/reconciler/v1alpha1/eventtype/eventtype.go index 0efe509885b..0d1ac11ef42 100644 --- a/pkg/reconciler/v1alpha1/eventtype/eventtype.go +++ b/pkg/reconciler/v1alpha1/eventtype/eventtype.go @@ -18,6 +18,7 @@ package eventtype import ( "context" + "fmt" "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" "github.com/knative/eventing/pkg/logging" @@ -199,9 +200,9 @@ func (r *reconciler) reconcile(ctx context.Context, et *v1alpha1.EventType) erro et.Status.MarkBrokerExists() if !b.Status.IsReady() { - logging.FromContext(ctx).Error("Broker is not ready", zap.Error(err)) + logging.FromContext(ctx).Error("Broker is not ready", zap.String("broker", b.Name)) et.Status.MarkBrokerNotReady() - return err + return fmt.Errorf("broker %q not ready", b.Name) } et.Status.MarkBrokerReady() diff --git a/pkg/reconciler/v1alpha1/eventtype/eventtype_test.go b/pkg/reconciler/v1alpha1/eventtype/eventtype_test.go new file mode 100644 index 00000000000..6f771867f1e --- /dev/null +++ b/pkg/reconciler/v1alpha1/eventtype/eventtype_test.go @@ -0,0 +1,279 @@ +/* +Copyright 2019 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT 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 eventtype + +import ( + "context" + "errors" + "fmt" + "testing" + + "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" + controllertesting "github.com/knative/eventing/pkg/reconciler/testing" + "go.uber.org/zap" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/dynamic" + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/rest" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/fake" +) + +const ( + testNS = "test-namespace" + eventTypeName = "test-eventtype" + eventTypeType = "test-type" + eventTypeBroker = "test-broker" +) + +var ( + trueVal = true + // deletionTime is used when objects are marked as deleted. Rfc3339Copy() + // truncates to seconds to match the loss of precision during serialization. + deletionTime = metav1.Now().Rfc3339Copy() + + // Map of events to set test cases' expectations easier. + events = map[string]corev1.Event{ + eventTypeReconciled: {Reason: eventTypeReconciled, Type: corev1.EventTypeNormal}, + eventTypeReconcileFailed: {Reason: eventTypeReconcileFailed, Type: corev1.EventTypeWarning}, + eventTypeUpdateStatusFailed: {Reason: eventTypeUpdateStatusFailed, Type: corev1.EventTypeWarning}, + } +) + +func init() { + // Add types to scheme + _ = v1alpha1.AddToScheme(scheme.Scheme) +} + +func TestProvideController(t *testing.T) { + // TODO(grantr) This needs a mock of manager.Manager. Creating a manager + // with a fake Config fails because the Manager tries to contact the + // apiserver. + + // cfg := &rest.Config{ + // Host: "http://foo:80", + // } + // + // mgr, err := manager.New(cfg, manager.Options{}) + // if err != nil { + // t.Fatalf("Error creating manager: %v", err) + // } + // + // _, err = ProvideController(mgr) + // if err != nil { + // t.Fatalf("Error in ProvideController: %v", err) + // } +} + +func TestInjectClient(t *testing.T) { + r := &reconciler{} + orig := r.client + n := fake.NewFakeClient() + if orig == n { + t.Errorf("Original and new clients are identical: %v", orig) + } + err := r.InjectClient(n) + if err != nil { + t.Errorf("Unexpected error injecting the client: %v", err) + } + if n != r.client { + t.Errorf("Unexpected client. Expected: '%v'. Actual: '%v'", n, r.client) + } +} + +func TestInjectConfig(t *testing.T) { + r := &reconciler{} + wantCfg := &rest.Config{ + Host: "http://foo", + } + + err := r.InjectConfig(wantCfg) + if err != nil { + t.Fatalf("Unexpected error injecting the config: %v", err) + } + + wantDynClient, err := dynamic.NewForConfig(wantCfg) + if err != nil { + t.Fatalf("Unexpected error generating dynamic client: %v", err) + } + + // Since dynamicClient doesn't export any fields, we can only test its type. + switch r.dynamicClient.(type) { + case dynamic.Interface: + // ok + default: + t.Errorf("Unexpected dynamicClient type. Expected: %T, Got: %T", wantDynClient, r.dynamicClient) + } +} + +func TestReconcile(t *testing.T) { + testCases := []controllertesting.TestCase{ + { + Name: "EventType not found", + }, + { + Name: "Get EventType error", + Scheme: scheme.Scheme, + Mocks: controllertesting.Mocks{ + MockGets: []controllertesting.MockGet{ + func(_ client.Client, _ context.Context, _ client.ObjectKey, obj runtime.Object) (controllertesting.MockHandled, error) { + if _, ok := obj.(*v1alpha1.EventType); ok { + return controllertesting.Handled, errors.New("test error getting the EventType") + } + return controllertesting.Unhandled, nil + }, + }, + }, + WantErrMsg: "test error getting the EventType", + }, + { + Name: "EventType being deleted", + Scheme: scheme.Scheme, + InitialState: []runtime.Object{ + makeDeletingEventType(), + }, + WantEvent: []corev1.Event{events[eventTypeReconciled]}, + }, + { + Name: "Get Broker error", + Scheme: scheme.Scheme, + InitialState: []runtime.Object{ + makeEventType(), + }, + Mocks: controllertesting.Mocks{ + MockGets: []controllertesting.MockGet{ + func(_ client.Client, _ context.Context, _ client.ObjectKey, obj runtime.Object) (controllertesting.MockHandled, error) { + if _, ok := obj.(*v1alpha1.Broker); ok { + return controllertesting.Handled, errors.New("test error getting broker") + } + return controllertesting.Unhandled, nil + }, + }, + }, + WantErrMsg: "test error getting broker", + WantEvent: []corev1.Event{events[eventTypeReconcileFailed]}, + }, + { + Name: "Broker not ready", + Scheme: scheme.Scheme, + InitialState: []runtime.Object{ + makeEventType(), + makeBroker(), + }, + WantErrMsg: `broker "` + eventTypeBroker + `" not ready`, + WantEvent: []corev1.Event{events[eventTypeReconcileFailed]}, + }, + { + Name: "EventType reconciliation success", + Scheme: scheme.Scheme, + InitialState: []runtime.Object{ + makeEventType(), + makeBrokerReady(), + }, + WantEvent: []corev1.Event{events[eventTypeReconciled]}, + WantPresent: []runtime.Object{ + makeReadyEventType(), + }, + }, + } + for _, tc := range testCases { + c := tc.GetClient() + dc := tc.GetDynamicClient() + recorder := tc.GetEventRecorder() + + r := &reconciler{ + client: c, + dynamicClient: dc, + recorder: recorder, + logger: zap.NewNop(), + } + tc.ReconcileKey = fmt.Sprintf("%s/%s", testNS, eventTypeName) + tc.IgnoreTimes = true + t.Run(tc.Name, tc.Runner(t, r, c, recorder)) + } +} + +func makeEventType() *v1alpha1.EventType { + return &v1alpha1.EventType{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "eventing.knative.dev/v1alpha1", + Kind: "EventType", + }, + ObjectMeta: metav1.ObjectMeta{ + Namespace: testNS, + Name: eventTypeName, + }, + Spec: v1alpha1.EventTypeSpec{ + Broker: eventTypeBroker, + Type: eventTypeType, + }, + } +} + +func makeReadyEventType() *v1alpha1.EventType { + t := makeEventType() + t.Status.InitializeConditions() + t.Status.MarkBrokerExists() + t.Status.MarkBrokerReady() + return t +} + +func makeDeletingEventType() *v1alpha1.EventType { + et := makeReadyEventType() + et.DeletionTimestamp = &deletionTime + return et +} + +func makeBroker() *v1alpha1.Broker { + return &v1alpha1.Broker{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "eventing.knative.dev/v1alpha1", + Kind: "Broker", + }, + ObjectMeta: metav1.ObjectMeta{ + Namespace: testNS, + Name: eventTypeBroker, + }, + Spec: v1alpha1.BrokerSpec{ + ChannelTemplate: &v1alpha1.ChannelSpec{ + Provisioner: makeChannelProvisioner(), + }, + }, + } +} + +func makeBrokerReady() *v1alpha1.Broker { + b := makeBroker() + b.Status.InitializeConditions() + b.Status.MarkTriggerChannelReady() + b.Status.MarkFilterReady() + b.Status.MarkIngressReady() + b.Status.SetAddress("test-address") + b.Status.MarkIngressChannelReady() + b.Status.MarkIngressSubscriptionReady() + return b +} + +func makeChannelProvisioner() *corev1.ObjectReference { + return &corev1.ObjectReference{ + APIVersion: "eventing.knative.dev/v1alpha1", + Kind: "ClusterChannelProvisioner", + Name: "my-provisioner", + } +} diff --git a/pkg/reconciler/v1alpha1/namespace/namespace_test.go b/pkg/reconciler/v1alpha1/namespace/namespace_test.go index be60e4a9828..729d7a9e086 100644 --- a/pkg/reconciler/v1alpha1/namespace/namespace_test.go +++ b/pkg/reconciler/v1alpha1/namespace/namespace_test.go @@ -52,9 +52,11 @@ var ( // map of events to set test cases' expectations easier events = map[string]corev1.Event{ - brokerCreated: {Reason: brokerCreated, Type: corev1.EventTypeNormal}, - serviceAccountCreated: {Reason: serviceAccountCreated, Type: corev1.EventTypeNormal}, - serviceAccountRBACCreated: {Reason: serviceAccountRBACCreated, Type: corev1.EventTypeNormal}, + brokerCreated: {Reason: brokerCreated, Type: corev1.EventTypeNormal}, + filterServiceAccountCreated: {Reason: filterServiceAccountCreated, Type: corev1.EventTypeNormal}, + filterServiceAccountRBACCreated: {Reason: filterServiceAccountRBACCreated, Type: corev1.EventTypeNormal}, + ingressServiceAccountCreated: {Reason: ingressServiceAccountCreated, Type: corev1.EventTypeNormal}, + ingressServiceAccountRBACCreated: {Reason: ingressServiceAccountRBACCreated, Type: corev1.EventTypeNormal}, } ) @@ -192,7 +194,11 @@ func TestReconcile(t *testing.T) { WantAbsent: []runtime.Object{ makeBroker(), }, - WantEvent: []corev1.Event{events[serviceAccountCreated], events[serviceAccountRBACCreated]}, + WantEvent: []corev1.Event{ + events[filterServiceAccountCreated], + events[filterServiceAccountRBACCreated], + events[ingressServiceAccountCreated], + events[ingressServiceAccountRBACCreated]}, }, { Name: "Broker Found", @@ -201,7 +207,11 @@ func TestReconcile(t *testing.T) { makeNamespace(&enabled), makeBroker(), }, - WantEvent: []corev1.Event{events[serviceAccountCreated], events[serviceAccountRBACCreated]}, + WantEvent: []corev1.Event{ + events[filterServiceAccountCreated], + events[filterServiceAccountRBACCreated], + events[ingressServiceAccountCreated], + events[ingressServiceAccountRBACCreated]}, }, { Name: "Broker.Create fails", @@ -220,7 +230,11 @@ func TestReconcile(t *testing.T) { }, }, WantErrMsg: "test error creating the Broker", - WantEvent: []corev1.Event{events[serviceAccountCreated], events[serviceAccountRBACCreated]}, + WantEvent: []corev1.Event{ + events[filterServiceAccountCreated], + events[filterServiceAccountRBACCreated], + events[ingressServiceAccountCreated], + events[ingressServiceAccountRBACCreated]}, }, { Name: "Broker created", @@ -232,8 +246,10 @@ func TestReconcile(t *testing.T) { makeBroker(), }, WantEvent: []corev1.Event{ - events[serviceAccountCreated], - events[serviceAccountRBACCreated], + events[filterServiceAccountCreated], + events[filterServiceAccountRBACCreated], + events[ingressServiceAccountCreated], + events[ingressServiceAccountRBACCreated], events[brokerCreated]}, }, } From cb718190929443ae00f101d988e6e4106d77446d Mon Sep 17 00:00:00 2001 From: nachocano Date: Mon, 25 Mar 2019 10:01:52 -0700 Subject: [PATCH 186/221] Updating README for source --- docs/registry/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/registry/README.md b/docs/registry/README.md index a19ad7db0be..0556a09d5eb 100644 --- a/docs/registry/README.md +++ b/docs/registry/README.md @@ -41,7 +41,7 @@ modify those names to make them K8s-compliant, whenever we need to generate them - `type` is authoritative. This refers to the Cloud Event type as it enters into the eventing mesh. - `source`: an identifier of where we receive the event from. This might not necessarily be the Cloud Event source -attribute. +attribute. If we receive the event from our receive adaptors, the info might come in a Cloud Event custom extension (e.g., from). - `schema` is a URI with the EventType schema. It may be a JSON schema, a protobuf schema, etc. It is optional. From af1934b23a2a04164f523c293477c67c86f1dd98 Mon Sep 17 00:00:00 2001 From: nachocano Date: Mon, 25 Mar 2019 10:21:54 -0700 Subject: [PATCH 187/221] moving ToDNSSubdomain to utils --- pkg/broker/ingress.go | 25 +++---------------------- pkg/utils/utils.go | 21 +++++++++++++++++++++ 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/pkg/broker/ingress.go b/pkg/broker/ingress.go index a18ac2e7fb9..37169b65a71 100644 --- a/pkg/broker/ingress.go +++ b/pkg/broker/ingress.go @@ -19,12 +19,10 @@ package broker import ( "context" "fmt" - "regexp" - "strings" - "go.uber.org/zap" + "github.com/knative/eventing/pkg/utils" - "k8s.io/apimachinery/pkg/util/validation" + "go.uber.org/zap" "github.com/cloudevents/sdk-go/pkg/cloudevents" @@ -35,8 +33,6 @@ import ( ) var ( - // Only allow alphanumeric, '-' or '.'. - validChars = regexp.MustCompile(`[^-\.a-z0-9]+`) // EventType not found error. notFound = k8serrors.NewNotFound(eventingv1alpha1.Resource("eventtype"), "") ) @@ -144,7 +140,7 @@ func (p *IngressPolicy) makeEventType(event cloudevents.Event) *eventingv1alpha1 cloudEventType := event.Type() return &eventingv1alpha1.EventType{ ObjectMeta: metav1.ObjectMeta{ - GenerateName: fmt.Sprintf("%s-", toDNS1123Subdomain(cloudEventType)), + GenerateName: fmt.Sprintf("%s-", utils.ToDNS1123Subdomain(cloudEventType)), Namespace: p.namespace, }, Spec: eventingv1alpha1.EventTypeSpec{ @@ -155,18 +151,3 @@ func (p *IngressPolicy) makeEventType(event cloudevents.Event) *eventingv1alpha1 }, } } - -func toDNS1123Subdomain(cloudEventType string) string { - // If it is not a valid DNS1123 subdomain, make it a valid one. - if msgs := validation.IsDNS1123Subdomain(cloudEventType); len(msgs) != 0 { - // If the length exceeds the max, cut it and leave some room for the generated UUID. - if len(cloudEventType) > validation.DNS1123SubdomainMaxLength { - cloudEventType = cloudEventType[:validation.DNS1123SubdomainMaxLength-10] - } - cloudEventType = strings.ToLower(cloudEventType) - cloudEventType = validChars.ReplaceAllString(cloudEventType, "") - // Only start/end with alphanumeric. - cloudEventType = strings.Trim(cloudEventType, "-.") - } - return cloudEventType -} diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index 33482fc0523..7f227073349 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -20,8 +20,11 @@ import ( "bufio" "io" "os" + "regexp" "strings" "sync" + + "k8s.io/apimachinery/pkg/util/validation" ) const ( @@ -32,6 +35,9 @@ const ( var ( domainName string once sync.Once + + // Only allow alphanumeric, '-' or '.'. + validChars = regexp.MustCompile(`[^-\.a-z0-9]+`) ) // GetClusterDomainName returns cluster's domain name or an error @@ -67,3 +73,18 @@ func getClusterDomainName(r io.Reader) string { // For all abnormal cases return default domain name return defaultDomainName } + +func ToDNS1123Subdomain(name string) string { + // If it is not a valid DNS1123 subdomain, make it a valid one. + if msgs := validation.IsDNS1123Subdomain(name); len(msgs) != 0 { + // If the length exceeds the max, cut it and leave some room for the generated UUID. + if len(name) > validation.DNS1123SubdomainMaxLength { + name = name[:validation.DNS1123SubdomainMaxLength-10] + } + name = strings.ToLower(name) + name = validChars.ReplaceAllString(name, "") + // Only start/end with alphanumeric. + name = strings.Trim(name, "-.") + } + return name +} From 2bac3a6c3b89e80bf42e1e3d0d3670ba9b037f69 Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Mon, 25 Mar 2019 22:14:05 -0700 Subject: [PATCH 188/221] removing ommitempty --- pkg/apis/eventing/v1alpha1/eventtype_types.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/apis/eventing/v1alpha1/eventtype_types.go b/pkg/apis/eventing/v1alpha1/eventtype_types.go index 6c607e488fe..6403aa09f79 100644 --- a/pkg/apis/eventing/v1alpha1/eventtype_types.go +++ b/pkg/apis/eventing/v1alpha1/eventtype_types.go @@ -49,13 +49,13 @@ var _ runtime.Object = (*EventType)(nil) var _ webhook.GenericCRD = (*EventType)(nil) type EventTypeSpec struct { - Type string `json:"type,omitempty"` + Type string `json:"type"` // +optional Source string `json:"source,omitempty"` // +optional Schema string `json:"schema,omitempty"` - Broker string `json:"broker,omitempty"` + Broker string `json:"broker"` } // EventTypeStatus represents the current state of a EventType. From d51a96ff06840edeeea1fd36c2038ac688fea400 Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Mon, 25 Mar 2019 22:59:32 -0700 Subject: [PATCH 189/221] Using github.com/kelseyhightower/envconfig for env variables. --- Gopkg.lock | 9 + cmd/broker/ingress/main.go | 51 +-- .../v1alpha1/broker/resources/ingress.go | 4 +- third_party/VENDOR-LICENSE | 25 ++ .../kelseyhightower/envconfig/LICENSE | 19 ++ .../kelseyhightower/envconfig/doc.go | 8 + .../kelseyhightower/envconfig/env_os.go | 7 + .../kelseyhightower/envconfig/env_syscall.go | 7 + .../kelseyhightower/envconfig/envconfig.go | 319 ++++++++++++++++++ .../kelseyhightower/envconfig/usage.go | 158 +++++++++ 10 files changed, 582 insertions(+), 25 deletions(-) create mode 100644 vendor/github.com/kelseyhightower/envconfig/LICENSE create mode 100644 vendor/github.com/kelseyhightower/envconfig/doc.go create mode 100644 vendor/github.com/kelseyhightower/envconfig/env_os.go create mode 100644 vendor/github.com/kelseyhightower/envconfig/env_syscall.go create mode 100644 vendor/github.com/kelseyhightower/envconfig/envconfig.go create mode 100644 vendor/github.com/kelseyhightower/envconfig/usage.go diff --git a/Gopkg.lock b/Gopkg.lock index ead8714dd5c..9224fed5537 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -358,6 +358,14 @@ pruneopts = "NUT" revision = "f2b4162afba35581b6d4a50d3b8f34e33c144682" +[[projects]] + digest = "1:b8870bf2606dca65dc382f4cb8b7a434f17ff36a915451bda12788e9620be368" + name = "github.com/kelseyhightower/envconfig" + packages = ["."] + pruneopts = "NUT" + revision = "f611eb38b3875cc3bd991ca91c51d06446afa14c" + version = "v1.3.0" + [[projects]] digest = "1:0836bde83bdc49aae7710e22d04e2555d9bd25cd133fbb78508c492307081aea" name = "github.com/knative/build" @@ -1263,6 +1271,7 @@ "github.com/fsnotify/fsnotify", "github.com/google/go-cmp/cmp", "github.com/google/go-cmp/cmp/cmpopts", + "github.com/kelseyhightower/envconfig", "github.com/knative/build/pkg/apis/build/v1alpha1", "github.com/knative/pkg/apis", "github.com/knative/pkg/apis/duck", diff --git a/cmd/broker/ingress/main.go b/cmd/broker/ingress/main.go index b817072d835..ced2185c920 100644 --- a/cmd/broker/ingress/main.go +++ b/cmd/broker/ingress/main.go @@ -24,14 +24,13 @@ import ( "log" "net/http" "net/url" - "os" - "strconv" "sync" "time" "github.com/cloudevents/sdk-go/pkg/cloudevents" ceclient "github.com/cloudevents/sdk-go/pkg/cloudevents/client" cehttp "github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http" + "github.com/kelseyhightower/envconfig" eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" "github.com/knative/eventing/pkg/broker" "github.com/knative/eventing/pkg/provisioners" @@ -58,6 +57,23 @@ var ( wg sync.WaitGroup ) +type envConfig struct { + // Channel where to send the cloudevents. + Channel string `envconfig:"CHANNEL"` + + // Broker name for this ingress. + Broker string `envconfig:"BROKER" required:"true"` + + // Namespace of this ingress. + Namespace string `envconfig:"NAMESPACE" required:"true"` + + // To indicate whether the ingress should allow any event. + AllowAny bool `envconfig:"ALLOW_ANY" required:"true"` + + // To indicate whether the ingress should auto-register unknown events. + AutoAdd bool `envconfig:"AUTO_ADD" required:"true"` +} + func main() { logConfig := provisioners.NewLoggingConfig() logger := provisioners.NewProvisionerLoggerFromConfig(logConfig).Desugar() @@ -65,9 +81,14 @@ func main() { flag.Parse() crlog.SetLogger(crlog.ZapLogger(false)) + var env envConfig + if err := envconfig.Process("", &env); err != nil { + log.Fatal("Failed to process env var", zap.Error(err)) + } + logger.Info("Starting...") - namespace := getRequiredEnv("NAMESPACE") + namespace := env.Namespace mgr, err := manager.New(config.GetConfigOrDie(), manager.Options{ Namespace: namespace, @@ -80,19 +101,19 @@ func main() { logger.Fatal("Unable to add eventingv1alpha1 scheme", zap.Error(err)) } - brokerName := getRequiredEnv("BROKER") + brokerName := env.Broker channelURI := &url.URL{ Scheme: "http", - Host: getRequiredEnv("CHANNEL"), + Host: env.Channel, Path: "/", } client := mgr.GetClient() policySpec := &eventingv1alpha1.IngressPolicySpec{ - AllowAny: asBool(getRequiredEnv("POLICY_ALLOW_ANY")), - AutoAdd: asBool(getRequiredEnv("POLICY_AUTO_ADD")), + AllowAny: env.AllowAny, + AutoAdd: env.AutoAdd, } ingressPolicy := broker.NewPolicy(logger, client, policySpec, namespace, brokerName, true) @@ -166,22 +187,6 @@ func main() { logger.Info("Done.") } -func getRequiredEnv(envKey string) string { - val, defined := os.LookupEnv(envKey) - if !defined { - log.Fatalf("required environment variable not defined '%s'", envKey) - } - return val -} - -func asBool(envVal string) bool { - b, err := strconv.ParseBool(envVal) - if err != nil { - log.Fatalf("required environment variable not bool %q", envVal) - } - return b -} - type handler struct { logger *zap.Logger ceClient ceclient.Client diff --git a/pkg/reconciler/v1alpha1/broker/resources/ingress.go b/pkg/reconciler/v1alpha1/broker/resources/ingress.go index 330eb4cb198..9637aef8306 100644 --- a/pkg/reconciler/v1alpha1/broker/resources/ingress.go +++ b/pkg/reconciler/v1alpha1/broker/resources/ingress.go @@ -83,11 +83,11 @@ func MakeIngress(args *IngressArgs) *appsv1.Deployment { Value: args.Broker.Name, }, { - Name: "POLICY_AUTO_ADD", + Name: "AUTO_ADD", Value: strconv.FormatBool(args.Broker.Spec.IngressPolicy.AutoAdd), }, { - Name: "POLICY_ALLOW_ANY", + Name: "ALLOW_ANY", Value: strconv.FormatBool(args.Broker.Spec.IngressPolicy.AllowAny), }, { diff --git a/third_party/VENDOR-LICENSE b/third_party/VENDOR-LICENSE index bdfec23c2a0..90d9e964fed 100644 --- a/third_party/VENDOR-LICENSE +++ b/third_party/VENDOR-LICENSE @@ -2845,6 +2845,31 @@ SOFTWARE. +=========================================================== +Import: github.com/knative/eventing/vendor/github.com/kelseyhightower/envconfig + +Copyright (c) 2013 Kelsey Hightower + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + + =========================================================== Import: github.com/knative/eventing/vendor/github.com/knative/pkg diff --git a/vendor/github.com/kelseyhightower/envconfig/LICENSE b/vendor/github.com/kelseyhightower/envconfig/LICENSE new file mode 100644 index 00000000000..4bfa7a84d81 --- /dev/null +++ b/vendor/github.com/kelseyhightower/envconfig/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2013 Kelsey Hightower + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/kelseyhightower/envconfig/doc.go b/vendor/github.com/kelseyhightower/envconfig/doc.go new file mode 100644 index 00000000000..f28561cd1cb --- /dev/null +++ b/vendor/github.com/kelseyhightower/envconfig/doc.go @@ -0,0 +1,8 @@ +// Copyright (c) 2013 Kelsey Hightower. All rights reserved. +// Use of this source code is governed by the MIT License that can be found in +// the LICENSE file. + +// Package envconfig implements decoding of environment variables based on a user +// defined specification. A typical use is using environment variables for +// configuration settings. +package envconfig diff --git a/vendor/github.com/kelseyhightower/envconfig/env_os.go b/vendor/github.com/kelseyhightower/envconfig/env_os.go new file mode 100644 index 00000000000..a6a014a2b47 --- /dev/null +++ b/vendor/github.com/kelseyhightower/envconfig/env_os.go @@ -0,0 +1,7 @@ +// +build appengine + +package envconfig + +import "os" + +var lookupEnv = os.LookupEnv diff --git a/vendor/github.com/kelseyhightower/envconfig/env_syscall.go b/vendor/github.com/kelseyhightower/envconfig/env_syscall.go new file mode 100644 index 00000000000..9d98085b99f --- /dev/null +++ b/vendor/github.com/kelseyhightower/envconfig/env_syscall.go @@ -0,0 +1,7 @@ +// +build !appengine + +package envconfig + +import "syscall" + +var lookupEnv = syscall.Getenv diff --git a/vendor/github.com/kelseyhightower/envconfig/envconfig.go b/vendor/github.com/kelseyhightower/envconfig/envconfig.go new file mode 100644 index 00000000000..892d74699f6 --- /dev/null +++ b/vendor/github.com/kelseyhightower/envconfig/envconfig.go @@ -0,0 +1,319 @@ +// Copyright (c) 2013 Kelsey Hightower. All rights reserved. +// Use of this source code is governed by the MIT License that can be found in +// the LICENSE file. + +package envconfig + +import ( + "encoding" + "errors" + "fmt" + "reflect" + "regexp" + "strconv" + "strings" + "time" +) + +// ErrInvalidSpecification indicates that a specification is of the wrong type. +var ErrInvalidSpecification = errors.New("specification must be a struct pointer") + +// A ParseError occurs when an environment variable cannot be converted to +// the type required by a struct field during assignment. +type ParseError struct { + KeyName string + FieldName string + TypeName string + Value string + Err error +} + +// Decoder has the same semantics as Setter, but takes higher precedence. +// It is provided for historical compatibility. +type Decoder interface { + Decode(value string) error +} + +// Setter is implemented by types can self-deserialize values. +// Any type that implements flag.Value also implements Setter. +type Setter interface { + Set(value string) error +} + +func (e *ParseError) Error() string { + return fmt.Sprintf("envconfig.Process: assigning %[1]s to %[2]s: converting '%[3]s' to type %[4]s. details: %[5]s", e.KeyName, e.FieldName, e.Value, e.TypeName, e.Err) +} + +// varInfo maintains information about the configuration variable +type varInfo struct { + Name string + Alt string + Key string + Field reflect.Value + Tags reflect.StructTag +} + +// GatherInfo gathers information about the specified struct +func gatherInfo(prefix string, spec interface{}) ([]varInfo, error) { + expr := regexp.MustCompile("([^A-Z]+|[A-Z][^A-Z]+|[A-Z]+)") + s := reflect.ValueOf(spec) + + if s.Kind() != reflect.Ptr { + return nil, ErrInvalidSpecification + } + s = s.Elem() + if s.Kind() != reflect.Struct { + return nil, ErrInvalidSpecification + } + typeOfSpec := s.Type() + + // over allocate an info array, we will extend if needed later + infos := make([]varInfo, 0, s.NumField()) + for i := 0; i < s.NumField(); i++ { + f := s.Field(i) + ftype := typeOfSpec.Field(i) + if !f.CanSet() || ftype.Tag.Get("ignored") == "true" { + continue + } + + for f.Kind() == reflect.Ptr { + if f.IsNil() { + if f.Type().Elem().Kind() != reflect.Struct { + // nil pointer to a non-struct: leave it alone + break + } + // nil pointer to struct: create a zero instance + f.Set(reflect.New(f.Type().Elem())) + } + f = f.Elem() + } + + // Capture information about the config variable + info := varInfo{ + Name: ftype.Name, + Field: f, + Tags: ftype.Tag, + Alt: strings.ToUpper(ftype.Tag.Get("envconfig")), + } + + // Default to the field name as the env var name (will be upcased) + info.Key = info.Name + + // Best effort to un-pick camel casing as separate words + if ftype.Tag.Get("split_words") == "true" { + words := expr.FindAllStringSubmatch(ftype.Name, -1) + if len(words) > 0 { + var name []string + for _, words := range words { + name = append(name, words[0]) + } + + info.Key = strings.Join(name, "_") + } + } + if info.Alt != "" { + info.Key = info.Alt + } + if prefix != "" { + info.Key = fmt.Sprintf("%s_%s", prefix, info.Key) + } + info.Key = strings.ToUpper(info.Key) + infos = append(infos, info) + + if f.Kind() == reflect.Struct { + // honor Decode if present + if decoderFrom(f) == nil && setterFrom(f) == nil && textUnmarshaler(f) == nil { + innerPrefix := prefix + if !ftype.Anonymous { + innerPrefix = info.Key + } + + embeddedPtr := f.Addr().Interface() + embeddedInfos, err := gatherInfo(innerPrefix, embeddedPtr) + if err != nil { + return nil, err + } + infos = append(infos[:len(infos)-1], embeddedInfos...) + + continue + } + } + } + return infos, nil +} + +// Process populates the specified struct based on environment variables +func Process(prefix string, spec interface{}) error { + infos, err := gatherInfo(prefix, spec) + + for _, info := range infos { + + // `os.Getenv` cannot differentiate between an explicitly set empty value + // and an unset value. `os.LookupEnv` is preferred to `syscall.Getenv`, + // but it is only available in go1.5 or newer. We're using Go build tags + // here to use os.LookupEnv for >=go1.5 + value, ok := lookupEnv(info.Key) + if !ok && info.Alt != "" { + value, ok = lookupEnv(info.Alt) + } + + def := info.Tags.Get("default") + if def != "" && !ok { + value = def + } + + req := info.Tags.Get("required") + if !ok && def == "" { + if req == "true" { + return fmt.Errorf("required key %s missing value", info.Key) + } + continue + } + + err := processField(value, info.Field) + if err != nil { + return &ParseError{ + KeyName: info.Key, + FieldName: info.Name, + TypeName: info.Field.Type().String(), + Value: value, + Err: err, + } + } + } + + return err +} + +// MustProcess is the same as Process but panics if an error occurs +func MustProcess(prefix string, spec interface{}) { + if err := Process(prefix, spec); err != nil { + panic(err) + } +} + +func processField(value string, field reflect.Value) error { + typ := field.Type() + + decoder := decoderFrom(field) + if decoder != nil { + return decoder.Decode(value) + } + // look for Set method if Decode not defined + setter := setterFrom(field) + if setter != nil { + return setter.Set(value) + } + + if t := textUnmarshaler(field); t != nil { + return t.UnmarshalText([]byte(value)) + } + + if typ.Kind() == reflect.Ptr { + typ = typ.Elem() + if field.IsNil() { + field.Set(reflect.New(typ)) + } + field = field.Elem() + } + + switch typ.Kind() { + case reflect.String: + field.SetString(value) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + var ( + val int64 + err error + ) + if field.Kind() == reflect.Int64 && typ.PkgPath() == "time" && typ.Name() == "Duration" { + var d time.Duration + d, err = time.ParseDuration(value) + val = int64(d) + } else { + val, err = strconv.ParseInt(value, 0, typ.Bits()) + } + if err != nil { + return err + } + + field.SetInt(val) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + val, err := strconv.ParseUint(value, 0, typ.Bits()) + if err != nil { + return err + } + field.SetUint(val) + case reflect.Bool: + val, err := strconv.ParseBool(value) + if err != nil { + return err + } + field.SetBool(val) + case reflect.Float32, reflect.Float64: + val, err := strconv.ParseFloat(value, typ.Bits()) + if err != nil { + return err + } + field.SetFloat(val) + case reflect.Slice: + vals := strings.Split(value, ",") + sl := reflect.MakeSlice(typ, len(vals), len(vals)) + for i, val := range vals { + err := processField(val, sl.Index(i)) + if err != nil { + return err + } + } + field.Set(sl) + case reflect.Map: + pairs := strings.Split(value, ",") + mp := reflect.MakeMap(typ) + for _, pair := range pairs { + kvpair := strings.Split(pair, ":") + if len(kvpair) != 2 { + return fmt.Errorf("invalid map item: %q", pair) + } + k := reflect.New(typ.Key()).Elem() + err := processField(kvpair[0], k) + if err != nil { + return err + } + v := reflect.New(typ.Elem()).Elem() + err = processField(kvpair[1], v) + if err != nil { + return err + } + mp.SetMapIndex(k, v) + } + field.Set(mp) + } + + return nil +} + +func interfaceFrom(field reflect.Value, fn func(interface{}, *bool)) { + // it may be impossible for a struct field to fail this check + if !field.CanInterface() { + return + } + var ok bool + fn(field.Interface(), &ok) + if !ok && field.CanAddr() { + fn(field.Addr().Interface(), &ok) + } +} + +func decoderFrom(field reflect.Value) (d Decoder) { + interfaceFrom(field, func(v interface{}, ok *bool) { d, *ok = v.(Decoder) }) + return d +} + +func setterFrom(field reflect.Value) (s Setter) { + interfaceFrom(field, func(v interface{}, ok *bool) { s, *ok = v.(Setter) }) + return s +} + +func textUnmarshaler(field reflect.Value) (t encoding.TextUnmarshaler) { + interfaceFrom(field, func(v interface{}, ok *bool) { t, *ok = v.(encoding.TextUnmarshaler) }) + return t +} diff --git a/vendor/github.com/kelseyhightower/envconfig/usage.go b/vendor/github.com/kelseyhightower/envconfig/usage.go new file mode 100644 index 00000000000..184635380f2 --- /dev/null +++ b/vendor/github.com/kelseyhightower/envconfig/usage.go @@ -0,0 +1,158 @@ +// Copyright (c) 2016 Kelsey Hightower and others. All rights reserved. +// Use of this source code is governed by the MIT License that can be found in +// the LICENSE file. + +package envconfig + +import ( + "encoding" + "fmt" + "io" + "os" + "reflect" + "strconv" + "strings" + "text/tabwriter" + "text/template" +) + +const ( + // DefaultListFormat constant to use to display usage in a list format + DefaultListFormat = `This application is configured via the environment. The following environment +variables can be used: +{{range .}} +{{usage_key .}} + [description] {{usage_description .}} + [type] {{usage_type .}} + [default] {{usage_default .}} + [required] {{usage_required .}}{{end}} +` + // DefaultTableFormat constant to use to display usage in a tabluar format + DefaultTableFormat = `This application is configured via the environment. The following environment +variables can be used: + +KEY TYPE DEFAULT REQUIRED DESCRIPTION +{{range .}}{{usage_key .}} {{usage_type .}} {{usage_default .}} {{usage_required .}} {{usage_description .}} +{{end}}` +) + +var ( + decoderType = reflect.TypeOf((*Decoder)(nil)).Elem() + setterType = reflect.TypeOf((*Setter)(nil)).Elem() + unmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem() +) + +func implementsInterface(t reflect.Type) bool { + return t.Implements(decoderType) || + reflect.PtrTo(t).Implements(decoderType) || + t.Implements(setterType) || + reflect.PtrTo(t).Implements(setterType) || + t.Implements(unmarshalerType) || + reflect.PtrTo(t).Implements(unmarshalerType) +} + +// toTypeDescription converts Go types into a human readable description +func toTypeDescription(t reflect.Type) string { + switch t.Kind() { + case reflect.Array, reflect.Slice: + return fmt.Sprintf("Comma-separated list of %s", toTypeDescription(t.Elem())) + case reflect.Map: + return fmt.Sprintf( + "Comma-separated list of %s:%s pairs", + toTypeDescription(t.Key()), + toTypeDescription(t.Elem()), + ) + case reflect.Ptr: + return toTypeDescription(t.Elem()) + case reflect.Struct: + if implementsInterface(t) && t.Name() != "" { + return t.Name() + } + return "" + case reflect.String: + name := t.Name() + if name != "" && name != "string" { + return name + } + return "String" + case reflect.Bool: + name := t.Name() + if name != "" && name != "bool" { + return name + } + return "True or False" + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + name := t.Name() + if name != "" && !strings.HasPrefix(name, "int") { + return name + } + return "Integer" + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + name := t.Name() + if name != "" && !strings.HasPrefix(name, "uint") { + return name + } + return "Unsigned Integer" + case reflect.Float32, reflect.Float64: + name := t.Name() + if name != "" && !strings.HasPrefix(name, "float") { + return name + } + return "Float" + } + return fmt.Sprintf("%+v", t) +} + +// Usage writes usage information to stderr using the default header and table format +func Usage(prefix string, spec interface{}) error { + // The default is to output the usage information as a table + // Create tabwriter instance to support table output + tabs := tabwriter.NewWriter(os.Stdout, 1, 0, 4, ' ', 0) + + err := Usagef(prefix, spec, tabs, DefaultTableFormat) + tabs.Flush() + return err +} + +// Usagef writes usage information to the specified io.Writer using the specifed template specification +func Usagef(prefix string, spec interface{}, out io.Writer, format string) error { + + // Specify the default usage template functions + functions := template.FuncMap{ + "usage_key": func(v varInfo) string { return v.Key }, + "usage_description": func(v varInfo) string { return v.Tags.Get("desc") }, + "usage_type": func(v varInfo) string { return toTypeDescription(v.Field.Type()) }, + "usage_default": func(v varInfo) string { return v.Tags.Get("default") }, + "usage_required": func(v varInfo) (string, error) { + req := v.Tags.Get("required") + if req != "" { + reqB, err := strconv.ParseBool(req) + if err != nil { + return "", err + } + if reqB { + req = "true" + } + } + return req, nil + }, + } + + tmpl, err := template.New("envconfig").Funcs(functions).Parse(format) + if err != nil { + return err + } + + return Usaget(prefix, spec, out, tmpl) +} + +// Usaget writes usage information to the specified io.Writer using the specified template +func Usaget(prefix string, spec interface{}, out io.Writer, tmpl *template.Template) error { + // gather first + infos, err := gatherInfo(prefix, spec) + if err != nil { + return err + } + + return tmpl.Execute(out, infos) +} From 46dec0b66ee23bd45535499145b0ac8f37a52b61 Mon Sep 17 00:00:00 2001 From: nachocano Date: Tue, 26 Mar 2019 13:14:25 -0700 Subject: [PATCH 190/221] changing Triggers to also look for an extension attribute as part of its source. If there, then we use that as source for exact matching. --- pkg/broker/receiver.go | 15 +++++++-- pkg/broker/receiver_test.go | 62 ++++++++++++++++++++++++++++++++----- 2 files changed, 68 insertions(+), 9 deletions(-) diff --git a/pkg/broker/receiver.go b/pkg/broker/receiver.go index c21279ba989..a190286d4c5 100644 --- a/pkg/broker/receiver.go +++ b/pkg/broker/receiver.go @@ -37,6 +37,8 @@ const ( defaultPort = 8080 writeTimeout = 1 * time.Minute + + extensionFrom = "From" ) // Receiver parses Cloud Events, determines if they pass a filter, and sends them to a subscriber. @@ -209,8 +211,17 @@ func (r *Receiver) shouldSendMessage(ts *eventingv1alpha1.TriggerSpec, event *cl return false } filterSource := ts.Filter.SourceAndType.Source - s := event.Context.AsV01().Source - actualSource := s.String() + actualSource := event.Source() + // We look if there is a From extension, which means that it is a known type that came from our sources. + // If it is there, then we update the actualSource variable and compare against this one. + // This is a hack not to change how we define trigger filters. + // TODO should be updated once we decide on filtering languages. + var from string + err := event.ExtensionAs(extensionFrom, &from) + if err == nil { + actualSource = from + } + if filterSource != eventingv1alpha1.TriggerAnyFilter && filterSource != actualSource { r.logger.Debug("Wrong source", zap.String("trigger.spec.filter.sourceAndType.source", filterSource), zap.String("message.source", actualSource)) return false diff --git a/pkg/broker/receiver_test.go b/pkg/broker/receiver_test.go index e7797111a45..083080f668e 100644 --- a/pkg/broker/receiver_test.go +++ b/pkg/broker/receiver_test.go @@ -25,6 +25,8 @@ import ( "net/url" "testing" + "sigs.k8s.io/controller-runtime/pkg/client" + "github.com/cloudevents/sdk-go/pkg/cloudevents" cehttp "github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http" "github.com/cloudevents/sdk-go/pkg/cloudevents/types" @@ -36,16 +38,15 @@ import ( v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/client-go/kubernetes/scheme" - "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" ) const ( - testNS = "test-namespace" - triggerName = "test-trigger" - eventType = `com.example.someevent` - eventSource = `/mycontext` - + testNS = "test-namespace" + triggerName = "test-trigger" + eventType = `com.example.someevent` + eventSource = `/mycontext` + eventFrom = `myfrom` toBeReplaced = "toBeReplaced" ) @@ -64,6 +65,7 @@ func TestReceiver(t *testing.T) { mocks controllertesting.Mocks tctx *cehttp.TransportContext requestFails bool + sendEvent cloudevents.Event returnedEvent *cloudevents.Event expectNewToFail bool expectedErr bool @@ -80,6 +82,7 @@ func TestReceiver(t *testing.T) { }, }, expectNewToFail: true, + sendEvent: makeEvent(), }, "Not POST": { tctx: &cehttp.TransportContext{ @@ -88,6 +91,7 @@ func TestReceiver(t *testing.T) { URI: "/", }, expectedStatus: http.StatusMethodNotAllowed, + sendEvent: makeEvent(), }, "Other path": { tctx: &cehttp.TransportContext{ @@ -96,6 +100,7 @@ func TestReceiver(t *testing.T) { URI: "/someotherEndpoint", }, expectedStatus: http.StatusNotFound, + sendEvent: makeEvent(), }, "Bad host": { tctx: &cehttp.TransportContext{ @@ -104,37 +109,44 @@ func TestReceiver(t *testing.T) { URI: "/", }, expectedErr: true, + sendEvent: makeEvent(), }, "Trigger.Get fails": { // No trigger exists, so the Get will fail. expectedErr: true, + sendEvent: makeEvent(), }, "Trigger doesn't have SubscriberURI": { triggers: []*eventingv1alpha1.Trigger{ makeTriggerWithoutSubscriberURI(), }, expectedErr: true, + sendEvent: makeEvent(), }, "Trigger with bad SubscriberURI": { triggers: []*eventingv1alpha1.Trigger{ makeTriggerWithBadSubscriberURI(), }, expectedErr: true, + sendEvent: makeEvent(), }, "Trigger without a Filter": { triggers: []*eventingv1alpha1.Trigger{ makeTriggerWithoutFilter(), }, + sendEvent: makeEvent(), }, "Wrong type": { triggers: []*eventingv1alpha1.Trigger{ makeTrigger("some-other-type", "Any"), }, + sendEvent: makeEvent(), }, "Wrong source": { triggers: []*eventingv1alpha1.Trigger{ makeTrigger("Any", "some-other-source"), }, + sendEvent: makeEvent(), }, "Dispatch failed": { triggers: []*eventingv1alpha1.Trigger{ @@ -143,24 +155,41 @@ func TestReceiver(t *testing.T) { requestFails: true, expectedErr: true, expectedDispatch: true, + sendEvent: makeEvent(), }, "Dispatch succeeded - Any": { triggers: []*eventingv1alpha1.Trigger{ makeTrigger("Any", "Any"), }, expectedDispatch: true, + sendEvent: makeEvent(), }, "Dispatch succeeded - Specific": { triggers: []*eventingv1alpha1.Trigger{ makeTrigger(eventType, eventSource), }, expectedDispatch: true, + sendEvent: makeEvent(), + }, + "Wrong source - From": { + triggers: []*eventingv1alpha1.Trigger{ + makeTrigger(eventType, eventSource), + }, + sendEvent: makeEventWithFrom(), + }, + "Dispatch succeeded - From Specific": { + triggers: []*eventingv1alpha1.Trigger{ + makeTrigger(eventType, eventFrom), + }, + expectedDispatch: true, + sendEvent: makeEventWithFrom(), }, "Returned Cloud Event": { triggers: []*eventingv1alpha1.Trigger{ makeTrigger("Any", "Any"), }, expectedDispatch: true, + sendEvent: makeEvent(), returnedEvent: makeDifferentEvent(), }, "Returned Cloud Event with custom headers": { @@ -199,6 +228,7 @@ func TestReceiver(t *testing.T) { "X-Ot-Foo": []string{"haden"}, }, expectedDispatch: true, + sendEvent: makeEvent(), returnedEvent: makeDifferentEvent(), }, } @@ -245,7 +275,7 @@ func TestReceiver(t *testing.T) { } ctx := cehttp.WithTransportContext(context.Background(), *tctx) resp := &cloudevents.EventResponse{} - err = r.serveHTTP(ctx, makeEvent(), resp) + err = r.serveHTTP(ctx, tc.sendEvent, resp) if tc.expectedErr && err == nil { t.Errorf("Expected an error, received nil") @@ -397,3 +427,21 @@ func makeDifferentEvent() *cloudevents.Event { }, } } + +func makeEventWithFrom() cloudevents.Event { + extensions := map[string]interface{}{ + extensionFrom: eventFrom, + } + return cloudevents.Event{ + Context: cloudevents.EventContextV02{ + Type: eventType, + Source: types.URLRef{ + URL: url.URL{ + Path: eventSource, + }, + }, + ContentType: cloudevents.StringOfApplicationJSON(), + Extensions: extensions, + }, + } +} From 3cf68752fbb25e5cdb09a27ecb5b55b02a0e219c Mon Sep 17 00:00:00 2001 From: nachocano Date: Tue, 26 Mar 2019 14:20:39 -0700 Subject: [PATCH 191/221] Updating ingress to read From custom extension, if present, and use that Otherwise it uses source --- pkg/broker/context.go | 6 ++++ pkg/broker/ingress.go | 24 ++++++++++++--- pkg/broker/ingress_test.go | 61 +++++++++++++++++++++++++------------- pkg/broker/receiver.go | 2 -- 4 files changed, 66 insertions(+), 27 deletions(-) diff --git a/pkg/broker/context.go b/pkg/broker/context.go index 7900eac6221..6b15faeb4fa 100644 --- a/pkg/broker/context.go +++ b/pkg/broker/context.go @@ -27,6 +27,12 @@ import ( "k8s.io/apimachinery/pkg/util/sets" ) +const ( + // Custom extension to match the EventType, if present. + // Otherwise we use the CloudEvent source attribute. + extensionFrom = "From" +) + var ( // These MUST be lowercase strings, as they will be compared against lowercase strings. forwardHeaders = sets.NewString( diff --git a/pkg/broker/ingress.go b/pkg/broker/ingress.go index 37169b65a71..3ac3e31fd09 100644 --- a/pkg/broker/ingress.go +++ b/pkg/broker/ingress.go @@ -105,6 +105,8 @@ func (p *IngressPolicy) isRegistered(ctx context.Context, event cloudevents.Even } func (p *IngressPolicy) getEventType(ctx context.Context, event cloudevents.Event) (*eventingv1alpha1.EventType, error) { + source := sourceOrFrom(event) + opts := &client.ListOptions{ Namespace: p.namespace, // Set Raw because if we need to get more than one page, then we will put the continue token @@ -120,9 +122,9 @@ func (p *IngressPolicy) getEventType(ctx context.Context, event cloudevents.Even } for _, et := range etl.Items { if et.Spec.Broker == p.broker { - // Matching on type and schemaURL, although this does not uniquely identify the EventType. - // If we match on source, then we will never find the EventType. - if et.Spec.Type == event.Type() && et.Spec.Schema == event.SchemaURL() { + // Matching on type, schemaURL, and "source" (either the CloudEvent source or our custom extension). + // Note that if we end up using the CloudEvent source, most probably the EventType won't be there. + if et.Spec.Type == event.Type() && et.Spec.Source == source && et.Spec.Schema == event.SchemaURL() { return &et, nil } } @@ -137,6 +139,7 @@ func (p *IngressPolicy) getEventType(ctx context.Context, event cloudevents.Even // makeEventType generates, but does not create an EventType from the given cloudevents.Event. func (p *IngressPolicy) makeEventType(event cloudevents.Event) *eventingv1alpha1.EventType { + source := sourceOrFrom(event) cloudEventType := event.Type() return &eventingv1alpha1.EventType{ ObjectMeta: metav1.ObjectMeta{ @@ -145,9 +148,22 @@ func (p *IngressPolicy) makeEventType(event cloudevents.Event) *eventingv1alpha1 }, Spec: eventingv1alpha1.EventTypeSpec{ Type: cloudEventType, - Source: event.Source(), + Source: source, Schema: event.SchemaURL(), Broker: p.broker, }, } } + +func sourceOrFrom(event cloudevents.Event) string { + source := event.Source() + // Use the custom extension 'from' as opposed to CloudEvent source, if available. + // If the extension is populated, it means the event came from one of our sources. + // Note that some of our sources might not populate this, e.g., container source, etc. + var from string + err := event.ExtensionAs(extensionFrom, &from) + if err == nil { + source = from + } + return source +} diff --git a/pkg/broker/ingress_test.go b/pkg/broker/ingress_test.go index 3bf0337e3ab..cc7b02bff52 100644 --- a/pkg/broker/ingress_test.go +++ b/pkg/broker/ingress_test.go @@ -45,6 +45,7 @@ const ( testType = "test-type" otherType = "other-test-type" testSource = "/test-source" + testFrom = "/test-from" ) func init() { @@ -53,13 +54,18 @@ func init() { } func TestIngress(t *testing.T) { + + extensions := map[string]interface{}{ + extensionFrom: testFrom, + } + testCases := map[string]struct { eventTypes []*eventingv1alpha1.EventType mocks controllertesting.Mocks event cloudevents.Event policySpec *eventingv1alpha1.IngressPolicySpec want bool - // TODO add wantPresent to check creation of an EventType + // TODO add wantPresent to check creation of an EventType. }{ "allow any, accept": { policySpec: &eventingv1alpha1.IngressPolicySpec{ @@ -71,7 +77,7 @@ func TestIngress(t *testing.T) { policySpec: &eventingv1alpha1.IngressPolicySpec{ AllowAny: false, }, - event: makeCloudEvent(), + event: makeCloudEvent(nil), mocks: controllertesting.Mocks{ MockLists: []controllertesting.MockList{ func(_ client.Client, _ context.Context, _ *client.ListOptions, _ runtime.Object) (controllertesting.MockHandled, error) { @@ -85,9 +91,19 @@ func TestIngress(t *testing.T) { policySpec: &eventingv1alpha1.IngressPolicySpec{ AllowAny: false, }, - event: makeCloudEvent(), + event: makeCloudEvent(nil), eventTypes: []*eventingv1alpha1.EventType{ - makeDifferentEventType(), + makeEventType(otherType, testSource), + }, + want: false, + }, + "allow registered, event not found with from, reject": { + policySpec: &eventingv1alpha1.IngressPolicySpec{ + AllowAny: false, + }, + event: makeCloudEvent(extensions), + eventTypes: []*eventingv1alpha1.EventType{ + makeEventType(testType, testSource), }, want: false, }, @@ -95,9 +111,19 @@ func TestIngress(t *testing.T) { policySpec: &eventingv1alpha1.IngressPolicySpec{ AllowAny: false, }, - event: makeCloudEvent(), + event: makeCloudEvent(nil), eventTypes: []*eventingv1alpha1.EventType{ - makeEventType(), + makeEventType(testType, testSource), + }, + want: true, + }, + "allow registered, event registered with from, accept": { + policySpec: &eventingv1alpha1.IngressPolicySpec{ + AllowAny: false, + }, + event: makeCloudEvent(extensions), + eventTypes: []*eventingv1alpha1.EventType{ + makeEventType(testType, testFrom), }, want: true, }, @@ -105,7 +131,7 @@ func TestIngress(t *testing.T) { policySpec: &eventingv1alpha1.IngressPolicySpec{ AutoAdd: true, }, - event: makeCloudEvent(), + event: makeCloudEvent(nil), mocks: controllertesting.Mocks{ MockLists: []controllertesting.MockList{ func(_ client.Client, _ context.Context, _ *client.ListOptions, _ runtime.Object) (controllertesting.MockHandled, error) { @@ -119,7 +145,7 @@ func TestIngress(t *testing.T) { policySpec: &eventingv1alpha1.IngressPolicySpec{ AutoAdd: true, }, - event: makeCloudEvent(), + event: makeCloudEvent(nil), mocks: controllertesting.Mocks{ MockCreates: []controllertesting.MockCreate{ func(_ client.Client, _ context.Context, obj runtime.Object) (controllertesting.MockHandled, error) { @@ -133,12 +159,12 @@ func TestIngress(t *testing.T) { policySpec: &eventingv1alpha1.IngressPolicySpec{ AutoAdd: true, }, - event: makeCloudEvent(), + event: makeCloudEvent(nil), mocks: controllertesting.Mocks{ MockCreates: []controllertesting.MockCreate{ func(_ client.Client, _ context.Context, obj runtime.Object) (controllertesting.MockHandled, error) { et := obj.(*eventingv1alpha1.EventType) - expected := makeEventType().Spec + expected := makeEventType(testType, testSource).Spec if !equality.Semantic.DeepDerivative(et.Spec, expected) { return controllertesting.Handled, errors.New("error creating type") } @@ -176,7 +202,7 @@ func newClient(initial []runtime.Object, mocks controllertesting.Mocks) *control return controllertesting.NewMockClient(innerClient, mocks) } -func makeCloudEvent() cloudevents.Event { +func makeCloudEvent(extensions map[string]interface{}) cloudevents.Event { return cloudevents.Event{ Context: cloudevents.EventContextV02{ Type: testType, @@ -186,11 +212,12 @@ func makeCloudEvent() cloudevents.Event { }, }, ContentType: cloudevents.StringOfApplicationJSON(), + Extensions: extensions, }, } } -func makeEventTypeFor(eventType string) *eventingv1alpha1.EventType { +func makeEventType(eventType, eventSource string) *eventingv1alpha1.EventType { return &eventingv1alpha1.EventType{ ObjectMeta: metav1.ObjectMeta{ GenerateName: fmt.Sprintf("%s-", eventType), @@ -199,15 +226,7 @@ func makeEventTypeFor(eventType string) *eventingv1alpha1.EventType { Spec: eventingv1alpha1.EventTypeSpec{ Type: eventType, Broker: broker, - Source: testSource, + Source: eventSource, }, } } - -func makeEventType() *eventingv1alpha1.EventType { - return makeEventTypeFor(testType) -} - -func makeDifferentEventType() *eventingv1alpha1.EventType { - return makeEventTypeFor(otherType) -} diff --git a/pkg/broker/receiver.go b/pkg/broker/receiver.go index a190286d4c5..e62b2fba5a8 100644 --- a/pkg/broker/receiver.go +++ b/pkg/broker/receiver.go @@ -37,8 +37,6 @@ const ( defaultPort = 8080 writeTimeout = 1 * time.Minute - - extensionFrom = "From" ) // Receiver parses Cloud Events, determines if they pass a filter, and sends them to a subscriber. From 23f55024903be09fcf9808102271c2f1be70d988 Mon Sep 17 00:00:00 2001 From: nachocano Date: Tue, 26 Mar 2019 15:05:58 -0700 Subject: [PATCH 192/221] Updating comments --- docs/registry/example_broker_policies.yaml | 25 ++++++++++ docs/registry/example_eventtype.yaml | 47 +++++++++++++++++-- pkg/broker/context.go | 1 + pkg/broker/ingress.go | 26 +++++++--- pkg/broker/receiver.go | 3 +- .../v1alpha1/eventtype/eventtype.go | 4 +- .../v1alpha1/namespace/namespace.go | 1 - pkg/utils/utils.go | 3 +- 8 files changed, 94 insertions(+), 16 deletions(-) diff --git a/docs/registry/example_broker_policies.yaml b/docs/registry/example_broker_policies.yaml index 8badaa10e9f..f39d5127066 100644 --- a/docs/registry/example_broker_policies.yaml +++ b/docs/registry/example_broker_policies.yaml @@ -1,3 +1,23 @@ +# Copyright 2019 The Knative Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This file is a list of example Brokers with different policies. Each could be used independently. + +--- + +# By not specifying an IngressPolicy, the default will accept any event. + apiVersion: eventing.knative.dev/v1alpha1 kind: Broker metadata: @@ -5,6 +25,8 @@ metadata: --- +# By setting the IngressPolicy to allowAny, the broker will accept only events in the Registry. + apiVersion: eventing.knative.dev/v1alpha1 kind: Broker metadata: @@ -15,6 +37,9 @@ spec: --- +# By setting the IngressPolicy to autoAdd, the broker will accept any event and will add them to the Registry, if +# not present. + apiVersion: eventing.knative.dev/v1alpha1 kind: Broker metadata: diff --git a/docs/registry/example_eventtype.yaml b/docs/registry/example_eventtype.yaml index 8c4ded6fde4..b3b10d8e52a 100644 --- a/docs/registry/example_eventtype.yaml +++ b/docs/registry/example_eventtype.yaml @@ -1,11 +1,48 @@ +# Copyright 2019 The Knative Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +--- + +# This EventType creates an event type with type 'repo:push' and source +# 'my-user/my-repo', for the 'broker-allow-registered' Broker. + apiVersion: eventing.knative.dev/v1alpha1 kind: EventType metadata: - # advisory name: repopush spec: - # authoritative type: repo:push - source: user/repo - schema: http://schemas/repo/push - broker: broker-allow-any + source: my-user/my-repo + broker: broker-allow-registered + +--- + +# This Trigger matches all events of type 'repo:push' and source +# 'my-user/my-repo', that are sent to the 'broker-allow-registered' Broker. + +apiVersion: eventing.knative.dev/v1alpha1 +kind: Trigger +metadata: + name: filtering-event-type +spec: + filter: + sourceAndType: + type: repo:push + source: my-user/my-repo + broker: broker-allow-registered + subscriber: + ref: + apiVersion: serving.knative.dev/v1alpha1 + kind: Service + name: message-dumper diff --git a/pkg/broker/context.go b/pkg/broker/context.go index 6b15faeb4fa..8c178b24ea6 100644 --- a/pkg/broker/context.go +++ b/pkg/broker/context.go @@ -30,6 +30,7 @@ import ( const ( // Custom extension to match the EventType, if present. // Otherwise we use the CloudEvent source attribute. + // This should be hopefully populated by the sources that we have control over. extensionFrom = "From" ) diff --git a/pkg/broker/ingress.go b/pkg/broker/ingress.go index 3ac3e31fd09..a5daea76982 100644 --- a/pkg/broker/ingress.go +++ b/pkg/broker/ingress.go @@ -37,16 +37,20 @@ var ( notFound = k8serrors.NewNotFound(eventingv1alpha1.Resource("eventtype"), "") ) +// IngressPolicy parses Cloud Events, determines if they pass the Broker's policy, and sends them downstream. type IngressPolicy struct { logger *zap.SugaredLogger client client.Client namespace string broker string spec *eventingv1alpha1.IngressPolicySpec - async bool + // This bool flag is for UT purposes only. + async bool } +// NewPolicy creates an IngressPolicy for a particular Broker. func NewPolicy(logger *zap.Logger, client client.Client, spec *eventingv1alpha1.IngressPolicySpec, namespace, broker string, async bool) *IngressPolicy { + // TODO too many args, maybe use a builder or just remove this function. return &IngressPolicy{ logger: logger.Sugar(), client: client, @@ -57,7 +61,11 @@ func NewPolicy(logger *zap.Logger, client client.Client, spec *eventingv1alpha1. } } +// AllowEvent filters events based on the configured policy. func (p *IngressPolicy) AllowEvent(ctx context.Context, event cloudevents.Event) bool { + // 1. If autoAdd is set to true, then the event is accepted. In case it wasn't seen before, it is added to the Broker's registry. + // 2. If allowAny is set to false, then the event is only accepted if it's already in the Broker's registry. + // 3. If allowAny is set to true, then all events are allowed to enter the mesh. if p.spec.AutoAdd { return p.autoAdd(ctx, event) } @@ -67,11 +75,13 @@ func (p *IngressPolicy) AllowEvent(ctx context.Context, event cloudevents.Event) return true } +// autoAdd attempts to add the EventType corresponding to the CloudEvent if it's not available in the Registry. +// It always returns true. func (p *IngressPolicy) autoAdd(ctx context.Context, event cloudevents.Event) bool { addFunc := func(ctx context.Context) { _, err := p.getEventType(ctx, event) if k8serrors.IsNotFound(err) { - p.logger.Infof("EventType %q not found: Adding", event.Type()) + p.logger.Debugf("EventType %q not found: Adding", event.Type()) eventType := p.makeEventType(event) err := p.client.Create(ctx, eventType) if err != nil { @@ -92,10 +102,11 @@ func (p *IngressPolicy) autoAdd(ctx context.Context, event cloudevents.Event) bo return true } +// isRegistered returns whether the EventType corresponding to the CloudEvent is available in the Registry. func (p *IngressPolicy) isRegistered(ctx context.Context, event cloudevents.Event) bool { _, err := p.getEventType(ctx, event) if k8serrors.IsNotFound(err) { - p.logger.Warnf("EventType %q not found: Reject", event.Type()) + p.logger.Debugf("EventType %q not found: Reject", event.Type()) return false } else if err != nil { p.logger.Errorf("Error retrieving EventType %q: Reject, %v", event.Type(), err) @@ -104,6 +115,8 @@ func (p *IngressPolicy) isRegistered(ctx context.Context, event cloudevents.Even return true } +// getEventType retrieves the EventType from the Registry for the given cloudevents.Event. +// If it is not found, it returns an error. func (p *IngressPolicy) getEventType(ctx context.Context, event cloudevents.Event) (*eventingv1alpha1.EventType, error) { source := sourceOrFrom(event) @@ -155,11 +168,12 @@ func (p *IngressPolicy) makeEventType(event cloudevents.Event) *eventingv1alpha1 } } +// Retrieve the custom extension 'from' as opposed to CloudEvent source, if available. +// If the extension is populated, it means the event came from one of our sources. +// Note that some of our sources might not populate this, e.g., container source, etc., so we just retrieve the CloudEvent +// source. func sourceOrFrom(event cloudevents.Event) string { source := event.Source() - // Use the custom extension 'from' as opposed to CloudEvent source, if available. - // If the extension is populated, it means the event came from one of our sources. - // Note that some of our sources might not populate this, e.g., container source, etc. var from string err := event.ExtensionAs(extensionFrom, &from) if err == nil { diff --git a/pkg/broker/receiver.go b/pkg/broker/receiver.go index e62b2fba5a8..eeae59501eb 100644 --- a/pkg/broker/receiver.go +++ b/pkg/broker/receiver.go @@ -212,7 +212,8 @@ func (r *Receiver) shouldSendMessage(ts *eventingv1alpha1.TriggerSpec, event *cl actualSource := event.Source() // We look if there is a From extension, which means that it is a known type that came from our sources. // If it is there, then we update the actualSource variable and compare against this one. - // This is a hack not to change how we define trigger filters. + // This is a hack not to change how we define trigger filters, and to make the source field usable, without needing + // more advanced filtering. // TODO should be updated once we decide on filtering languages. var from string err := event.ExtensionAs(extensionFrom, &from) diff --git a/pkg/reconciler/v1alpha1/eventtype/eventtype.go b/pkg/reconciler/v1alpha1/eventtype/eventtype.go index 0d1ac11ef42..c6fc6586dcc 100644 --- a/pkg/reconciler/v1alpha1/eventtype/eventtype.go +++ b/pkg/reconciler/v1alpha1/eventtype/eventtype.go @@ -209,7 +209,7 @@ func (r *reconciler) reconcile(ctx context.Context, et *v1alpha1.EventType) erro return nil } -// updateStatus updates the event type's status. +// updateStatus updates the EventType's status. func (r *reconciler) updateStatus(eventType *v1alpha1.EventType) (*v1alpha1.EventType, error) { ctx := context.TODO() objectKey := client.ObjectKey{Namespace: eventType.Namespace, Name: eventType.Name} @@ -231,7 +231,7 @@ func (r *reconciler) updateStatus(eventType *v1alpha1.EventType) (*v1alpha1.Even return latestEventType, nil } -// getBroker returns the Broker for EventType 'et' if exists, otherwise it returns an error. +// getBroker returns the Broker for EventType 'et' if it exists, otherwise it returns an error. func (r *reconciler) getBroker(ctx context.Context, et *v1alpha1.EventType) (*v1alpha1.Broker, error) { b := &v1alpha1.Broker{} name := types.NamespacedName{ diff --git a/pkg/reconciler/v1alpha1/namespace/namespace.go b/pkg/reconciler/v1alpha1/namespace/namespace.go index 48e828d90b4..dc19a485fb4 100644 --- a/pkg/reconciler/v1alpha1/namespace/namespace.go +++ b/pkg/reconciler/v1alpha1/namespace/namespace.go @@ -225,7 +225,6 @@ func (r *reconciler) reconcileBrokerFilterServiceAccount(ctx context.Context, ns // reconcileBrokerIngressServiceAccount reconciles the Broker's ingress service account for Namespace 'ns'. func (r *reconciler) reconcileBrokerIngressServiceAccount(ctx context.Context, ns *corev1.Namespace) (*corev1.ServiceAccount, error) { - // TODO in order to get cluster-scoped EventTypes, we need a ClusterRoleBinding. return r.reconcileBrokerServiceAccount(ctx, ns, brokerIngressSA, ingressServiceAccountCreated) } diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index 7f227073349..ea067aaa43c 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -74,10 +74,11 @@ func getClusterDomainName(r io.Reader) string { return defaultDomainName } +// Converts 'name' to a valid DNS1123 subdomain, required for object names in K8s. func ToDNS1123Subdomain(name string) string { // If it is not a valid DNS1123 subdomain, make it a valid one. if msgs := validation.IsDNS1123Subdomain(name); len(msgs) != 0 { - // If the length exceeds the max, cut it and leave some room for the generated UUID. + // If the length exceeds the max, cut it and leave some room for a potential generated UUID. if len(name) > validation.DNS1123SubdomainMaxLength { name = name[:validation.DNS1123SubdomainMaxLength-10] } From 5ea6e2408f2123a33e7fff94ef6d86531047a306 Mon Sep 17 00:00:00 2001 From: nachocano Date: Tue, 26 Mar 2019 16:05:39 -0700 Subject: [PATCH 193/221] It seems to complaint if I add an invalid URL in the markup. Changing schema. --- docs/registry/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/registry/README.md b/docs/registry/README.md index 0556a09d5eb..41780ff28fe 100644 --- a/docs/registry/README.md +++ b/docs/registry/README.md @@ -29,7 +29,7 @@ metadata: spec: type: repo:push source: my-user/my-repo - schema: http://schemas/bitbucket/repo/push + schema: my-schema broker: default ``` @@ -167,7 +167,7 @@ NAME | TYPE | SOURCE | SCHEMA | BROKER | READY | REASON --- | --- | --- | --- | --- | --- | --- dev.knative.foo.bar-55wcn | dev.knative.foo.bar | dev.knative.example | | auto-add-demo | True | | repofork | repo:fork | my-other-user/my-other-repo | | dev | False | BrokerIsNotReady | -repopush | repo:push | my-other-user/my-other-repo | http://schemas/bitbucket/repo/push | default | True | | +repopush | repo:push | my-other-user/my-other-repo | my-schema | default | True | | dev.knative.source.github.push-34cnb | dev.knative.source.github.push | my-user/my-repo | | default | True | | dev.knative.source.github.pullrequest-86jhv | dev.knative.source.github.pull_request | my-user/my-repo | | default | True | | From 4eca34c6f3e47d96bbd5e454da303e3ba300c0ea Mon Sep 17 00:00:00 2001 From: nachocano Date: Wed, 27 Mar 2019 10:44:30 -0700 Subject: [PATCH 194/221] typo --- docs/registry/example_broker_policies.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/registry/example_broker_policies.yaml b/docs/registry/example_broker_policies.yaml index f39d5127066..999ea6f6ce8 100644 --- a/docs/registry/example_broker_policies.yaml +++ b/docs/registry/example_broker_policies.yaml @@ -25,7 +25,7 @@ metadata: --- -# By setting the IngressPolicy to allowAny, the broker will accept only events in the Registry. +# By setting the IngressPolicy to not allowAny, the broker will accept only events in the Registry. apiVersion: eventing.knative.dev/v1alpha1 kind: Broker From 657bc3729c3ccf09ce3bdf86cbdce3943a82af0c Mon Sep 17 00:00:00 2001 From: nachocano Date: Wed, 27 Mar 2019 14:56:49 -0700 Subject: [PATCH 195/221] lowercase from --- pkg/broker/context.go | 2 +- pkg/broker/ingress.go | 27 ++++++++++++++++----------- pkg/broker/ingress_test.go | 3 ++- 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/pkg/broker/context.go b/pkg/broker/context.go index 8c178b24ea6..ce3ee1197b0 100644 --- a/pkg/broker/context.go +++ b/pkg/broker/context.go @@ -31,7 +31,7 @@ const ( // Custom extension to match the EventType, if present. // Otherwise we use the CloudEvent source attribute. // This should be hopefully populated by the sources that we have control over. - extensionFrom = "From" + extensionFrom = "from" ) var ( diff --git a/pkg/broker/ingress.go b/pkg/broker/ingress.go index a5daea76982..b13065a7a96 100644 --- a/pkg/broker/ingress.go +++ b/pkg/broker/ingress.go @@ -50,7 +50,6 @@ type IngressPolicy struct { // NewPolicy creates an IngressPolicy for a particular Broker. func NewPolicy(logger *zap.Logger, client client.Client, spec *eventingv1alpha1.IngressPolicySpec, namespace, broker string, async bool) *IngressPolicy { - // TODO too many args, maybe use a builder or just remove this function. return &IngressPolicy{ logger: logger.Sugar(), client: client, @@ -72,6 +71,7 @@ func (p *IngressPolicy) AllowEvent(ctx context.Context, event cloudevents.Event) if !p.spec.AllowAny { return p.isRegistered(ctx, event) } + p.logger.Debugf("EventType %q received, Accept", event.Type()) return true } @@ -81,24 +81,28 @@ func (p *IngressPolicy) autoAdd(ctx context.Context, event cloudevents.Event) bo addFunc := func(ctx context.Context) { _, err := p.getEventType(ctx, event) if k8serrors.IsNotFound(err) { - p.logger.Debugf("EventType %q not found: Adding", event.Type()) + p.logger.Debugf("EventType %q not found: Registering", event.Type()) eventType := p.makeEventType(event) err := p.client.Create(ctx, eventType) if err != nil { - p.logger.Errorf("Error creating EventType %q: Accept but Not Add, %v", event.Type(), err) + p.logger.Errorf("Error registering EventType %q: %v", event.Type(), err) + } else { + p.logger.Debugf("EventType %q Registered", event.Type()) } } else if err != nil { - p.logger.Errorf("Error retrieving EventType %q: Accept but Not Add, %v", event.Type(), err) + p.logger.Errorf("Error retrieving EventType %q: %v", event.Type(), err) } } if p.async { // TODO do this in a working queue + // TODO should run some background task to dedupe EventTypes within Brokers. // Do not use the previous context as it seems that it can be canceled before // this routine executes. go addFunc(context.TODO()) } else { addFunc(ctx) } + p.logger.Debugf("EventType %q received, Accept", event.Type()) return true } @@ -106,19 +110,20 @@ func (p *IngressPolicy) autoAdd(ctx context.Context, event cloudevents.Event) bo func (p *IngressPolicy) isRegistered(ctx context.Context, event cloudevents.Event) bool { _, err := p.getEventType(ctx, event) if k8serrors.IsNotFound(err) { - p.logger.Debugf("EventType %q not found: Reject", event.Type()) + p.logger.Infof("EventType %q not found, Reject", event.Type()) return false } else if err != nil { - p.logger.Errorf("Error retrieving EventType %q: Reject, %v", event.Type(), err) + p.logger.Errorf("Error retrieving EventType %q, Reject: %v", event.Type(), err) return false } + p.logger.Debugf("EventType %q is registered, Accept", event.Type()) return true } // getEventType retrieves the EventType from the Registry for the given cloudevents.Event. // If it is not found, it returns an error. func (p *IngressPolicy) getEventType(ctx context.Context, event cloudevents.Event) (*eventingv1alpha1.EventType, error) { - source := sourceOrFrom(event) + source := fromOrSource(event) opts := &client.ListOptions{ Namespace: p.namespace, @@ -135,7 +140,7 @@ func (p *IngressPolicy) getEventType(ctx context.Context, event cloudevents.Even } for _, et := range etl.Items { if et.Spec.Broker == p.broker { - // Matching on type, schemaURL, and "source" (either the CloudEvent source or our custom extension). + // Matching on type, schemaURL, and "source" (either our custom extension 'from' or the CloudEvent source). // Note that if we end up using the CloudEvent source, most probably the EventType won't be there. if et.Spec.Type == event.Type() && et.Spec.Source == source && et.Spec.Schema == event.SchemaURL() { return &et, nil @@ -152,7 +157,7 @@ func (p *IngressPolicy) getEventType(ctx context.Context, event cloudevents.Even // makeEventType generates, but does not create an EventType from the given cloudevents.Event. func (p *IngressPolicy) makeEventType(event cloudevents.Event) *eventingv1alpha1.EventType { - source := sourceOrFrom(event) + source := fromOrSource(event) cloudEventType := event.Type() return &eventingv1alpha1.EventType{ ObjectMeta: metav1.ObjectMeta{ @@ -168,11 +173,11 @@ func (p *IngressPolicy) makeEventType(event cloudevents.Event) *eventingv1alpha1 } } -// Retrieve the custom extension 'from' as opposed to CloudEvent source, if available. +// Retrieve the custom extension 'From' as opposed to CloudEvent source, if available. // If the extension is populated, it means the event came from one of our sources. // Note that some of our sources might not populate this, e.g., container source, etc., so we just retrieve the CloudEvent // source. -func sourceOrFrom(event cloudevents.Event) string { +func fromOrSource(event cloudevents.Event) string { source := event.Source() var from string err := event.ExtensionAs(extensionFrom, &from) diff --git a/pkg/broker/ingress_test.go b/pkg/broker/ingress_test.go index cc7b02bff52..fb49903af93 100644 --- a/pkg/broker/ingress_test.go +++ b/pkg/broker/ingress_test.go @@ -71,7 +71,8 @@ func TestIngress(t *testing.T) { policySpec: &eventingv1alpha1.IngressPolicySpec{ AllowAny: true, }, - want: true, + event: makeCloudEvent(nil), + want: true, }, "allow registered, error listing types, reject": { policySpec: &eventingv1alpha1.IngressPolicySpec{ From 5f11229d35158b57758d87bb8f8e278735ca6aeb Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Thu, 28 Mar 2019 09:17:16 -0700 Subject: [PATCH 196/221] using new cloud event API --- pkg/broker/ttl.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/pkg/broker/ttl.go b/pkg/broker/ttl.go index 2cb03da350e..963487af789 100644 --- a/pkg/broker/ttl.go +++ b/pkg/broker/ttl.go @@ -29,9 +29,6 @@ const ( // SetTTL sets the TTL into the EventContext. ttl should be a positive integer. func SetTTL(ctx cloudevents.EventContext, ttl interface{}) cloudevents.EventContext { v2 := ctx.AsV02() - if v2.Extensions == nil { - v2.Extensions = make(map[string]interface{}) - } - v2.Extensions[V02TTLAttribute] = ttl + v2.SetExtension(V02TTLAttribute, ttl) return v2 } From 9f67f3cb0c85f76433ab747d9f3aaf454a53e7b2 Mon Sep 17 00:00:00 2001 From: nachocano Date: Thu, 28 Mar 2019 09:36:12 -0700 Subject: [PATCH 197/221] addressing Grant's comment. Debug instead of Info --- docs/registry/README.md | 17 ++++++++--------- pkg/broker/ingress.go | 2 +- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/docs/registry/README.md b/docs/registry/README.md index 41780ff28fe..24f8966027b 100644 --- a/docs/registry/README.md +++ b/docs/registry/README.md @@ -162,15 +162,14 @@ First, Event Consumers will list the EventTypes registered in the system `$ kubectl get eventtypes -n default` - -NAME | TYPE | SOURCE | SCHEMA | BROKER | READY | REASON ---- | --- | --- | --- | --- | --- | --- -dev.knative.foo.bar-55wcn | dev.knative.foo.bar | dev.knative.example | | auto-add-demo | True | | -repofork | repo:fork | my-other-user/my-other-repo | | dev | False | BrokerIsNotReady | -repopush | repo:push | my-other-user/my-other-repo | my-schema | default | True | | -dev.knative.source.github.push-34cnb | dev.knative.source.github.push | my-user/my-repo | | default | True | | -dev.knative.source.github.pullrequest-86jhv | dev.knative.source.github.pull_request | my-user/my-repo | | default | True | | - +``` +NAME TYPE SOURCE SCHEMA BROKER READY REASON +dev.knative.foo.bar-55wcn dev.knative.foo.bar dev.knative.example auto-add-demo True +repofork repo:fork my-other-user/my-other-repo dev False BrokerIsNotReady +repopush repo:push my-other-user/my-other-repo my-schema default True +dev.knative.source.github.push-34cnb dev.knative.source.github.push my-user/my-repo default True +dev.knative.source.github.pullrequest-86jhv dev.knative.source.github.pull_request my-user/my-repo default True +``` Then, they will be able to *easily* create the appropriate Trigger(s) diff --git a/pkg/broker/ingress.go b/pkg/broker/ingress.go index b13065a7a96..357011f285d 100644 --- a/pkg/broker/ingress.go +++ b/pkg/broker/ingress.go @@ -110,7 +110,7 @@ func (p *IngressPolicy) autoAdd(ctx context.Context, event cloudevents.Event) bo func (p *IngressPolicy) isRegistered(ctx context.Context, event cloudevents.Event) bool { _, err := p.getEventType(ctx, event) if k8serrors.IsNotFound(err) { - p.logger.Infof("EventType %q not found, Reject", event.Type()) + p.logger.Debugf("EventType %q not found, Reject", event.Type()) return false } else if err != nil { p.logger.Errorf("Error retrieving EventType %q, Reject: %v", event.Type(), err) From 3138555323fac95a1fddf05ca37fc65199c21c33 Mon Sep 17 00:00:00 2001 From: nachocano Date: Fri, 29 Mar 2019 11:38:34 -0700 Subject: [PATCH 198/221] Bumping cloud-sdk --- Gopkg.lock | 5 +++-- Gopkg.toml | 3 +-- .../sdk-go/pkg/cloudevents/transport/http/context.go | 5 +++-- .../sdk-go/pkg/cloudevents/transport/http/transport.go | 2 ++ 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index c259e031e7b..cee8b2319db 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -58,7 +58,7 @@ version = "v2.1.15" [[projects]] - digest = "1:fd1744b6351c378ab9c77159c50626d626069e878ef616b31a59f2e40131b222" + digest = "1:f616892b62757b2dcd70957602981d4f05c4d75017138cea02b3845d07c18785" name = "github.com/cloudevents/sdk-go" packages = [ "pkg/cloudevents", @@ -74,7 +74,8 @@ "pkg/cloudevents/types", ] pruneopts = "NUT" - revision = "b88e53efaaadf77c676a5b53f64c2dc8814e1c6a" + revision = "e00e75c8a1befe895cc00def1f88adb611195159" + version = "0.4.4" [[projects]] digest = "1:ffe9824d294da03b391f44e1ae8281281b4afc1bdaa9588c9097785e3af10cec" diff --git a/Gopkg.toml b/Gopkg.toml index 3d4cfee472f..9635a7d6472 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -144,5 +144,4 @@ required = [ [[constraint]] name = "github.com/cloudevents/sdk-go" - # HEAD as of 2019-03-21 - revision = "b88e53efaaadf77c676a5b53f64c2dc8814e1c6a" + version = "=0.4.4" diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http/context.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http/context.go index e809c3a31c8..9511ec6d239 100644 --- a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http/context.go +++ b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http/context.go @@ -147,11 +147,12 @@ func ContextWithHeader(ctx context.Context, key, value string) context.Context { // HeaderFrom extracts the header oject in the given context. Always returns a non-nil Header. func HeaderFrom(ctx context.Context) http.Header { + ch := http.Header{} header := ctx.Value(headerKey) if header != nil { if h, ok := header.(http.Header); ok { - return h + copyHeaders(h, ch) } } - return http.Header{} + return ch } diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http/transport.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http/transport.go index 39761c90dd6..5deeb69e53c 100644 --- a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http/transport.go +++ b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http/transport.go @@ -163,9 +163,11 @@ func (t *Transport) obsSend(ctx context.Context, event cloudevents.Event) (*clou if m, ok := msg.(*Message); ok { copyHeaders(m.Header, req.Header) + req.Body = ioutil.NopCloser(bytes.NewBuffer(m.Body)) req.ContentLength = int64(len(m.Body)) req.Close = true + return httpDo(ctx, t.Client, &req, func(resp *http.Response, err error) (*cloudevents.Event, error) { if err != nil { return nil, err From 9f4374c7efe29e121b9d97127f0216f06fd0b946 Mon Sep 17 00:00:00 2001 From: Scott Nichols Date: Fri, 29 Mar 2019 13:53:32 -0700 Subject: [PATCH 199/221] Migrate to correct sdk usage. --- pkg/broker/receiver.go | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/pkg/broker/receiver.go b/pkg/broker/receiver.go index 507c3af55ff..a03e730ed7b 100644 --- a/pkg/broker/receiver.go +++ b/pkg/broker/receiver.go @@ -34,8 +34,6 @@ import ( ) const ( - defaultPort = 8080 - writeTimeout = 1 * time.Minute ) @@ -44,17 +42,12 @@ type Receiver struct { logger *zap.Logger client client.Client ceClient ceclient.Client - ceHTTP *cehttp.Transport } // New creates a new Receiver and its associated MessageReceiver. The caller is responsible for // Start()ing the returned MessageReceiver. func New(logger *zap.Logger, client client.Client) (*Receiver, error) { - ceHTTP, err := cehttp.New(cehttp.WithBinaryEncoding(), cehttp.WithPort(defaultPort)) - if err != nil { - return nil, err - } - ceClient, err := ceclient.New(ceHTTP) + ceClient, err := ceclient.NewDefault() if err != nil { return nil, err } @@ -63,7 +56,6 @@ func New(logger *zap.Logger, client client.Client) (*Receiver, error) { logger: logger, client: client, ceClient: ceClient, - ceHTTP: ceHTTP, } err = r.initClient() if err != nil { @@ -204,7 +196,7 @@ func (r *Receiver) sendEvent(ctx context.Context, tctx cehttp.TransportContext, } sendingCTX := SendingContext(ctx, tctx, subscriberURI) - return r.ceHTTP.Send(sendingCTX, *event) + return r.ceClient.Send(sendingCTX, *event) } func (r *Receiver) getTrigger(ctx context.Context, ref provisioners.ChannelReference) (*eventingv1alpha1.Trigger, error) { From 7741e18de22f169937d6651b34feb921e3c8f72c Mon Sep 17 00:00:00 2001 From: nachocano Date: Wed, 10 Apr 2019 09:52:57 -0700 Subject: [PATCH 200/221] update README with other branch --- docs/registry/README.md | 270 ++++++++++++++++++++++++++++++++++------ 1 file changed, 234 insertions(+), 36 deletions(-) diff --git a/docs/registry/README.md b/docs/registry/README.md index 24f8966027b..e663ccb86a5 100644 --- a/docs/registry/README.md +++ b/docs/registry/README.md @@ -1,9 +1,29 @@ # Registry Proposal +## Problem + +As an `Event Consumer` I want to be able to discover the different event types that I can consume +from the different Brokers, without resorting to any OOB mechanism. +This is also known as the `discoverability` use case, and is the main focus of this proposal. + ## Objective -Design an **initial** version of the Registry that can support discoverability of -the different event types that can be consumed from the eventing mesh. +Design an **initial** version of the **Registry** for the **MVP** that can support discoverability of +the different event types that can be consumed from the eventing mesh. For details on the different user stories +that this proposal touches, please refer to the +[User stories and personas for Knative eventing](https://docs.google.com/document/d/15uhyqQvaomxRX2u8s0i6CNhA86BQTNztkdsLUnPmvv4/edit?usp=sharing) document. +Note that this proposal targets the cases were the Broker/Trigger model is used. + +#### Out of scope + +- Registry to Registry communication. This doesn't seem needed for an MVP. +- Security-related matters. Those are handled offline by the `Cluster Configurator`, e.g., the `Cluster Configurator` +takes care of setting up Secrets for connecting to a GitHub repo, and so on. +- Registry synchronization with `Event Producers`. We assume that if new GitHub events are created by +GitHub after our cluster has been configured (i.e., our GitHub CRD Source installed) and the appropriate webhooks +have been created, we will need to create new webhooks (and update the GitHub CRD Source) if we want to listen for +those new events. Until doing so, those new events shouldn't be listed in the Registry. +Such task will again be in charge of the `Cluster Configurator`. ## Requirements @@ -11,49 +31,64 @@ Our design revolves around the following core requirements: 1. We should have a Registry per namespace to enforce isolation. 2. The Registry should contain the event types that can be consumed from -the eventing mesh. If an event type is not ready for consumption, we should explicitly indicate so. +the eventing mesh in order to support the `discoverability` use case. +If an event type is not ready for consumption, we should explicitly indicate so (e.g., if the Broker +is not ready). 3. The event types stored in the Registry should contain all the required information for a consumer to create a Trigger without resorting to some other OOB mechanism. -## Design Ideas + +## Proposed Ideas ### EventType CRD -We propose having a namespaced EventType CRD. Here is an example of how a CR would look like: +We propose introducing a namespaced-EventType CRD. Here is an example of how a CR would look like: ```yaml apiVersion: eventing.knative.dev/v1alpha1 kind: EventType metadata: name: repopush + namespace: default spec: type: repo:push source: my-user/my-repo - schema: my-schema + schema: /my-schema broker: default ``` - -- The `name` of the EventType is advisory, non-authoritative. Given that Cloud Event types can +- The `name` of the EventType is advisory, non-authoritative. Given that CloudEvents types can contain characters that may not comply with Kubernetes naming conventions, we will (slightly) modify those names to make them K8s-compliant, whenever we need to generate them. -- `type` is authoritative. This refers to the Cloud Event type as it enters into the eventing mesh. +- `type` is authoritative. This refers to the CloudEvent type as it enters into the eventing mesh. + +- `source`: an identifier of where we receive the event from. This might not necessarily be the CloudEvent source +attribute. + +If we have control over the entity emitting the CloudEvent, as is the case of many of our receive adaptors, +then we propose to add a CloudEvent custom extension (e.g., from) with this information, to ease the creation of filters +on Triggers later on. +As the CloudEvent source attribute is somewhat useless (e.g., github pull requests are populated with `https://github.com///pull/`), +there is no way of doing exact matching of CloudEvent sources on Triggers. Thus, we propose adding this custom extension +to CloudEvents whenever we can. If the extension is not present, then we fallback to the CloudEvent source. +Note that when we start supporting more advanced filtering mechanisms on Triggers, we might not need this. Further, with the +addition of `subject`, the meaning of the CloudEvent source might change, and we might be better off then. This needs further +discussion. -- `source`: an identifier of where we receive the event from. This might not necessarily be the Cloud Event source -attribute. If we receive the event from our receive adaptors, the info might come in a Cloud Event custom extension (e.g., from). - `schema` is a URI with the EventType schema. It may be a JSON schema, a protobuf schema, etc. It is optional. - `broker` refers to the Broker that can provide the EventType. -### EventType Instantiation +### Typical Flow -We foresee the following ways of populating the Registry: +`1.` A `Cluster Configurator` configures the cluster in a way that allows the population of EventTypes in the Registry. +We foresee the following three ways of populating the Registry so far: -**1. Event Source CR installation** +`1.1` Event Source CR installation -Upon installation of an Event Source CR, the source will register its EventTypes. +Upon installation of an Event Source CR by a `Cluster Configurator`, the Source will register its EventTypes. Example: @@ -83,12 +118,49 @@ spec: ``` -By applying this file, two EventTypes will be registered, with types `push` and `pull_request`, -source `my-other-user/my-other-repo`, for the `default` Broker in the `default` namespace. +By applying the above file, two EventTypes will be registered, with types `dev.knative.source.github.push` and +`dev.knative.source.github.pull_request`, source `my-other-user/my-other-repo`, for the `default` Broker in the `default` + namespace, and with owner `github-source-sample`. This should be done by the Event Source controller, in this case, + the GitHubSource controller. + +Note that the `Cluster Configurator` is the person in charge of taking care of authentication-related matters. E.g., if a new `Event Consumer` +wants to listen for events from a different GitHub repo, the `Cluster Configurator` will take care of the necessary secrets generation, +and new Source instantiation. + +In YAML, the above EventTypes would look something like these: -**2. Manual User Registration** +```yaml +apiVersion: eventing.knative.dev/v1alpha1 +kind: EventType +metadata: + generateName: dev.knative.source.github.push- + namespace: default + owner: # Owned by github-source-sample +spec: + type: dev.knative.source.github.push + source: my-other-user/my-other-repo + broker: default +--- +apiVersion: eventing.knative.dev/v1alpha1 +kind: EventType +metadata: + generateName: dev.knative.source.github.pullrequest- + namespace: default + owner: # Owned by github-source-sample +spec: + type: dev.knative.source.github.pull_request + source: my-other-user/my-other-repo + broker: default +``` + +Two things to notice: +- We generate the names by stripping invalid characters from the original type (e.g., `_`) +- The `spec.type` adds the prefix `dev.knative.source.github.` This is a **separate discussion** on whether we should +change the (GitHub) types or not. + +`1.2.` Manual Registration -A user manually `kubectl applies` an EventType CR. +The `Cluster Configurator` manually `kubectl applies` an EventType CR. Example: @@ -107,11 +179,21 @@ spec: This would register the EventType named `repofork` with type `repo:fork`, source `my-other-user/my-other-repo` in the `dev` Broker of the `default` namespace. +As under the hood, `kubeclt apply` just makes a REST call to the API server with the appropriate RBAC permissions, +the `Cluster Configurator` can give EventType `create` permissions to trusted parties, so that they can register +their EventTypes. -**3. Broker Auto Registration Policy** -Upon arrival of a non-registered EventType to a Broker ingress, and in case the Broker -ingress policy allows auto-registration of EventTypes, the Broker will create the EventType. +`1.3` Broker Auto Registration Policy + +The `Cluster Configurator` configures the Broker ingress policy to allow auto-registration of EventTypes. +Upon arrival of a non-registered EventType to the Broker ingress, the Broker will then create that type. +Note that the creation of the EventType is done asynchronously, i.e., the CloudEvent is accepted and sent +to the appropriate Trigger(s) in parallel of the EventType creation. If the creation fails, on a subsequent arrival +there will be a new creation attempt. + +Although sub-optimal (as `Event Consumers` find out about EventTypes upon first arrival), we believe this mechanism (or something similar) +is needed for Sources where the `Cluster Configurator` does not know in advance the EventTypes they can produce (e.g., a ContainerSource). Example: @@ -149,30 +231,39 @@ curl -v "http://auto-add-demo-broker.default.svc.cluster.local/" \ ``` The Broker `auto-add-demo` will then create the EventType with type `dev.knative.foo.bar` in the Registry. +In YAML, the EventType would look something like these: -## Discoverability Use Case - -By adding the spec.* fields of EventType as custom columns in the CRD we can fulfill the discoverability -use case: +```yaml +apiVersion: eventing.knative.dev/v1alpha1 +kind: EventType +metadata: + generateName: dev.knative.foo.bar- + namespace: default + owner: # Owned by auto-add-demo? +spec: + type: dev.knative.foo.bar + source: dev.knative.example + broker: auto-add-demo +``` -*As an Event Consumer I want to be able to discover the different event types that I can consume -from the different Brokers, without resorting to any OOB mechanism.* +`2.` An `Event Consumer` checks the Registry to see what EventTypes it can consume from the mesh. -First, Event Consumers will list the EventTypes registered in the system +Example: `$ kubectl get eventtypes -n default` ``` -NAME TYPE SOURCE SCHEMA BROKER READY REASON -dev.knative.foo.bar-55wcn dev.knative.foo.bar dev.knative.example auto-add-demo True -repofork repo:fork my-other-user/my-other-repo dev False BrokerIsNotReady -repopush repo:push my-other-user/my-other-repo my-schema default True -dev.knative.source.github.push-34cnb dev.knative.source.github.push my-user/my-repo default True -dev.knative.source.github.pullrequest-86jhv dev.knative.source.github.pull_request my-user/my-repo default True +NAME TYPE SOURCE SCHEMA BROKER READY REASON +dev.knative.foo.bar-55wcn dev.knative.foo.bar dev.knative.example auto-add-demo True +repofork repo:fork my-other-user/my-other-repo dev False BrokerIsNotReady +repopush repo:push my-other-user/my-other-repo /my-schema default True +dev.knative.source.github.push-34cnb dev.knative.source.github.push my-user/my-repo default True +dev.knative.source.github.pullrequest-86jhv dev.knative.source.github.pull_request my-user/my-repo default True ``` -Then, they will be able to *easily* create the appropriate Trigger(s) +`3.` The `Event Consumer` creates a Trigger to listen to an EventType in the Registry. +Example: ```yaml apiVersion: eventing.knative.dev/v1alpha1 @@ -191,3 +282,110 @@ spec: kind: Service name: my-service ``` + +### Broker Ingress Policies + +We briefly mentioned configuring an ingress policy in the Broker so that it can auto-register EventTypes. +In order to support that, we propose adding an `ingressPolicy` field to the Broker's spec CRD. + +Below are two CR examples with Brokers configured using different policies. Note that the fields of +`ingressPolicy` might change (e.g., `ingressPolicy` might just end up being a string). +We are omitting Broker's fields irrelevant to this discussion. +Also note that such configuration is done by the `Cluster Configurator`. + +- Allow Registered + +By setting the ingress policy to not allow any, the Broker will accept only events with EventTypes in the Registry. + +```yaml +apiVersion: eventing.knative.dev/v1alpha1 +kind: Broker +metadata: + name: broker-allow-registered +spec: + ingressPolicy: + allowAny: false +``` + +- Auto Add + +By setting the ingress policy to auto add, the Broker will accept any event and will add its EventType +to the Registry (in case it is not present). + +```yaml +apiVersion: eventing.knative.dev/v1alpha1 +kind: Broker +metadata: + name: broker-auto-add +spec: + ingressPolicy: + autoAdd: true +``` + +By not specifying an ingress policy, we thought that the default behavior would be to accept any event, which is similar to `Auto Add` +but without registration of events. This needs further discussion. + +Note that more policies should probably need to be configured in the future, e.g., allow auto-registration of EventTypes received +from within the cluster (e.g., from a response of a Service running in the cluster) as opposed to external services, and so on. +We just enumerate two simple cases here. + +## FAQ + +Here is a list of frequently asked questions that may help clarify the scope of the Registry. + +- Is the Registry meant to be used just for creating Triggers or for also setting up Event Sources? + + It's mainly intended for helping the `Event Consumer` with the `discoverability` use case. Therefore, + it is meant for helping out creating Triggers. + +- If I have a simple use case where I'm just setting up an Event Source and my KnService is its Sink (i.e., no Triggers involved), +is there a need/use for the Registry? + + As stated before, this Registry proposal for the MVP helps creating Triggers, i.e., when you use the Broker/Trigger + model. As you can see in the EventType CRD, there is a mandatory `broker` field. If you are not sending events to a Broker, + then EventTypes won't be added to the Registry (at least in this proposal). + Implementation-wise, we can check whether the Source's sink kind is `Broker`, and if so, then register its EventTypes. + + +- Is the Registry meant to be used in a single-user environment where the same person is setting up both the Event Source and +the destination Sink? + + We believe is mainly intended for multi-user environment. A `Cluster Configurator` persona is in charge of setting up + the Sources, and `Event Consumers` are the ones that create the Triggers. Having said that, it can also be used in + a single-user environment, but the Registry might not add much value compared to what we have right now in terms of + `discoverability`, but it surely does in terms of, for example, `admission control`. + +- Does a user need to know which type of environment they're in before they should know if they should look at the Registry? +In other words, is a Registry always going to be there and if not under what conditions will it be? + + A Registry will always be there, i.e., `Event Consumers` will always be able to `kubectl get eventtypes -n `. + In case no CR Sources are pointing to Brokers, then the Registry will be empty. + +- Once an Event Source is created, how is a new one created with different auth in an env where the user is really just meant +to deal with Triggers? This may not be a Registry specific question but if one of the goals of the Registry is to make it +so that the user only deals with Triggers using the info in the Registry, I think this aspect comes into play. + + We believe the Event Source instantiation with different credentials should be handled by the `Cluster Configurer`. If the + `Cluster Configurer` persona happens to be the same person as the `Event Consumer` persona, then it will have to take care + of creating the Source. This is related to the question of a single-user, multi-user environment above. + +- I've heard conflicting messages around whether the Registry is just a list of Event Types or it will also be a list of +Event Sources so that the user doesn't need to query the CRDs to get the list. We need to be clear about this. + + The Registry is a list of EventTypes. Having said that, the `Event Consumer` could also (if it has the proper RBAC permissions) + list Event Sources (e.g., `kubectl get crds -l eventing.knative.dev/source=true`), but that list is not part of what we call + Registry here. The idea behind the fields in the EventType CRD is to have all the necessary information there in + order to create Triggers, thus, in most cases, the `Event Consumer` shouldn't have to list Sources. + +- I wonder if the Event Source populating the Registry should happen when the Event Source is loaded into the system, +meaning when the Event Source's CRD is installed (not when an instance of the CRD is created). + +The problem with that is that you don't have a namespace (nor Broker, user/repo, etc.) at that point. +Which namespace the EventType should be created on? Pointing to which Broker? +Implementation-wise, one potential solution is to have a controller for source CRDs, whenever one is installed, search for all the namespaces with +eventing enabled (`kubectl get namespaces -l knative-eventing-injection=enabled`), and adding all the possible EventTypes from that CRD to each of +the Brokers in those namespaces. A downside of this is that the Registry information is not "accurate", in the sense that it only has info about EventTypes +that may potentially flow in the system. But actually, they will only be able to flow when a CR is created. + +- ... + From bc3236b5985a7a847d0e6e8e92dbae339a5dcc39 Mon Sep 17 00:00:00 2001 From: nachocano Date: Wed, 10 Apr 2019 14:55:46 -0700 Subject: [PATCH 201/221] updating e2e tests --- test/builders.go | 88 +++++++++++++++++ test/crd.go | 1 + test/crd_checks.go | 45 +++++++++ test/e2e/e2e.go | 43 ++++++++ test/e2e/registry_test.go | 203 ++++++++++++++++++++++++++++++++++++++ test/states.go | 22 +++++ 6 files changed, 402 insertions(+) create mode 100644 test/e2e/registry_test.go diff --git a/test/builders.go b/test/builders.go index 23d7c6538e3..0d1f9b0a759 100644 --- a/test/builders.go +++ b/test/builders.go @@ -78,3 +78,91 @@ func (b *TriggerBuilder) SubscriberSvc(svcName string) *TriggerBuilder { } return b } + +// Builder for broker objects. +type BrokerBuilder struct { + *eventingv1alpha1.Broker +} + +func NewBrokerBuilder(name, namespace string) *BrokerBuilder { + broker := &eventingv1alpha1.Broker{ + TypeMeta: metav1.TypeMeta{ + APIVersion: eventingv1alpha1.SchemeGroupVersion.String(), + Kind: "Broker", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + }, + Spec: eventingv1alpha1.BrokerSpec{ + IngressPolicy: &eventingv1alpha1.IngressPolicySpec{ + AllowAny: true, + }, + }, + } + + return &BrokerBuilder{ + Broker: broker, + } +} + +func (b *BrokerBuilder) Build() *eventingv1alpha1.Broker { + return b.Broker.DeepCopy() +} + +func (b *BrokerBuilder) IngressPolicy(policy *eventingv1alpha1.IngressPolicySpec) *BrokerBuilder { + b.Broker.Spec.IngressPolicy = policy + return b +} + +// Builder for EventType objects. +type EventTypeBuilder struct { + *eventingv1alpha1.EventType +} + +func NewEventTypeBuilder(name, namespace string) *EventTypeBuilder { + eventType := &eventingv1alpha1.EventType{ + TypeMeta: metav1.TypeMeta{ + APIVersion: eventingv1alpha1.SchemeGroupVersion.String(), + Kind: "EventType", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + }, + Spec: eventingv1alpha1.EventTypeSpec{ + Broker: "default", + Type: CloudEventDefaultType, + Source: CloudEventDefaultSource, + Schema: "", + }, + } + + return &EventTypeBuilder{ + EventType: eventType, + } +} + +func (b *EventTypeBuilder) Build() *eventingv1alpha1.EventType { + return b.EventType.DeepCopy() +} + +func (b *EventTypeBuilder) Type(eventType string) *EventTypeBuilder { + b.Spec.Type = eventType + return b +} + +func (b *EventTypeBuilder) Source(eventSource string) *EventTypeBuilder { + b.Spec.Source = eventSource + return b +} + +func (b *EventTypeBuilder) Broker(brokerName string) *EventTypeBuilder { + b.Spec.Broker = brokerName + return b +} + +func (b *EventTypeBuilder) Schema(schema string) *EventTypeBuilder { + b.Spec.Schema = schema + return b +} diff --git a/test/crd.go b/test/crd.go index efbab8f3888..209fd400fc0 100644 --- a/test/crd.go +++ b/test/crd.go @@ -113,6 +113,7 @@ const ( CloudEventEncodingStructured = "structured" CloudEventDefaultEncoding = CloudEventEncodingBinary CloudEventDefaultType = "dev.knative.test.event" + CloudEventDefaultSource = "dev.knative.test.source" ) // EventSenderPod creates a Pod that sends a single event to the given address. diff --git a/test/crd_checks.go b/test/crd_checks.go index 4d0aa903c68..42c7ca0de2a 100644 --- a/test/crd_checks.go +++ b/test/crd_checks.go @@ -114,6 +114,29 @@ func WaitForTriggerState(client eventingclient.TriggerInterface, name string, in }) } +// WaitForEventTypeState polls the status of the EventType called name from client +// every interval until inState returns `true` indicating it is done, returns an +// error or timeout. desc will be used to name the metric that is emitted to +// track how long it took for name to get into the state checked by inState. +func WaitForEventTypeState(client eventingclient.EventTypeInterface, name string, inState func(r *eventingv1alpha1.EventType) (bool, error), desc string, timeout time.Duration) error { + metricName := fmt.Sprintf("WaitForEventTypeState/%s/%s", name, desc) + _, span := trace.StartSpan(context.Background(), metricName) + defer span.End() + + return wait.PollImmediate(interval, timeout, func() (bool, error) { + r, err := client.Get(name, metav1.GetOptions{}) + if k8serrors.IsNotFound(err) { + // Return false as we are not done yet. + // We swallow the error to keep on polling, + // as the event + return false, nil + } else if err != nil { + return true, err + } + return inState(r) + }) +} + // WaitForTriggersListState polls the status of the TriggerList // from client every interval until inState returns `true` indicating it // is done, returns an error or timeout. desc will be used to name the metric @@ -131,3 +154,25 @@ func WaitForTriggersListState(clients eventingclient.TriggerInterface, inState f return inState(t) }) } + +// WaitForEventTypeListState polls the status of the EventTypeList +// from client every interval until inState returns `true` indicating it +// is done, returns an error or timeout. desc will be used to name the metric +// that is emitted to track how long it took to get into the state checked by inState. +func WaitForEventTypeListState(clients eventingclient.EventTypeInterface, inState func(t *eventingv1alpha1.EventTypeList) (bool, error), desc string, timeout time.Duration) error { + metricName := fmt.Sprintf("WaitForEventTypeListState/%s", desc) + _, span := trace.StartSpan(context.Background(), metricName) + defer span.End() + + return wait.PollImmediate(interval, timeout, func() (bool, error) { + l, err := clients.List(metav1.ListOptions{}) + if err != nil { + return true, err + } + // If there are no items, then we return false as we are not done yet. + if len(l.Items) == 0 { + return false, nil + } + return inState(l) + }) +} diff --git a/test/e2e/e2e.go b/test/e2e/e2e.go index 020b6a87f45..7246bd45e50 100644 --- a/test/e2e/e2e.go +++ b/test/e2e/e2e.go @@ -181,6 +181,17 @@ func CreateTrigger(clients *test.Clients, trigger *v1alpha1.Trigger, logf loggin return nil } +// CreateEventType will create an EventType. +func CreateEventType(clients *test.Clients, eventType *v1alpha1.EventType, logf logging.FormatLogger, cleaner *test.Cleaner) error { + eventTypes := clients.Eventing.EventingV1alpha1().EventTypes(eventType.Namespace) + res, err := eventTypes.Create(eventType) + if err != nil { + return err + } + cleaner.Add(v1alpha1.SchemeGroupVersion.Group, v1alpha1.SchemeGroupVersion.Version, "eventtypes", eventType.Namespace, res.ObjectMeta.Name) + return nil +} + // WithTriggerReady creates a Trigger and waits until it is Ready. func WithTriggerReady(clients *test.Clients, trigger *v1alpha1.Trigger, logf logging.FormatLogger, cleaner *test.Cleaner) error { if err := CreateTrigger(clients, trigger, logf, cleaner); err != nil { @@ -201,6 +212,29 @@ func WithTriggerReady(clients *test.Clients, trigger *v1alpha1.Trigger, logf log return nil } +// WithEventTypeReady creates an EventType and waits until it is Ready. +func WithEventTypeReady(clients *test.Clients, eventType *v1alpha1.EventType, logf logging.FormatLogger, cleaner *test.Cleaner) error { + if err := CreateEventType(clients, eventType, logf, cleaner); err != nil { + return err + } + return WaitForEventTypeReady(clients, eventType) +} + +// WaitForEventTypeReady waits until the EventType is Ready. +func WaitForEventTypeReady(clients *test.Clients, eventType *v1alpha1.EventType) error { + eventTypes := clients.Eventing.EventingV1alpha1().EventTypes(eventType.Namespace) + if err := test.WaitForEventTypeState(eventTypes, eventType.Name, test.IsEventTypeReady, "EventTypeIsReady", time.Minute); err != nil { + return err + } + // Update the given object so they'll reflect the ready state. + updatedEventType, err := eventTypes.Get(eventType.Name, metav1.GetOptions{}) + if err != nil { + return err + } + updatedEventType.DeepCopyInto(eventType) + return nil +} + // CreateServiceAccount will create a service account func CreateServiceAccount(clients *test.Clients, sa *corev1.ServiceAccount, _ logging.FormatLogger, cleaner *test.Cleaner) error { sas := clients.Kube.Kube.CoreV1().ServiceAccounts(pkgTest.Flags.Namespace) @@ -379,6 +413,15 @@ func WaitForAllTriggersReady(clients *test.Clients, logf logging.FormatLogger, n return nil } +// WaitForAllEventTypesReady will wait until all EventTypes in the given namespace are ready. +func WaitForAllEventTypesReady(clients *test.Clients, logf logging.FormatLogger, namespace string) error { + eventTypes := clients.Eventing.EventingV1alpha1().EventTypes(namespace) + if err := test.WaitForEventTypeListState(eventTypes, test.EventTypesReady, "EventTypeIsReady", timeout); err != nil { + return err + } + return nil +} + // LabelNamespace labels the test namespace with the labels map. func LabelNamespace(clients *test.Clients, logf logging.FormatLogger, labels map[string]string) error { ns := pkgTest.Flags.Namespace diff --git a/test/e2e/registry_test.go b/test/e2e/registry_test.go new file mode 100644 index 00000000000..a70d0054011 --- /dev/null +++ b/test/e2e/registry_test.go @@ -0,0 +1,203 @@ +// +build e2e + +/* +Copyright 2019 The Knative Authors +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT 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 e2e + +import ( + "fmt" + "testing" + "time" + + "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" + + "github.com/knative/eventing/test" + pkgTest "github.com/knative/pkg/test" + "k8s.io/apimachinery/pkg/util/uuid" +) + +// Helper to setup test data and expectations. +type testFixture struct { + ingressPolicy *v1alpha1.IngressPolicySpec + preRegisterEvent bool + wantEventDelivered bool + wantEventRegistered bool +} + +func TestRegistryBrokerAllowAny(t *testing.T) { + fixture := &testFixture{ + ingressPolicy: &v1alpha1.IngressPolicySpec{ + AllowAny: true, + }, + wantEventDelivered: true, + } + Registry(t, fixture) +} + +func TestRegistryBrokerAllowRegisteredAndEventPreRegistered(t *testing.T) { + fixture := &testFixture{ + ingressPolicy: &v1alpha1.IngressPolicySpec{ + AllowAny: false, + }, + preRegisterEvent: true, + wantEventDelivered: true, + wantEventRegistered: true, + } + Registry(t, fixture) +} + +func TestRegistryBrokerAllowRegisteredAndEventNotPreRegistered(t *testing.T) { + fixture := &testFixture{ + ingressPolicy: &v1alpha1.IngressPolicySpec{ + AllowAny: false, + }, + } + Registry(t, fixture) +} + +func TestRegistryBrokerAutoAdd(t *testing.T) { + fixture := &testFixture{ + ingressPolicy: &v1alpha1.IngressPolicySpec{ + AutoAdd: true, + }, + wantEventDelivered: true, + wantEventRegistered: true, + } + Registry(t, fixture) +} + +func Registry(t *testing.T, fixture *testFixture) { + clients, cleaner := Setup(t, t.Logf) + + ns, cleanupNS := CreateNamespaceIfNeeded(t, clients, t.Logf) + + defer cleanupNS() + defer TearDown(clients, cleaner, t.Logf) + + // Define the constants here to avoid conflicts with other e2e tests. + const ( + brokerName = "test-broker" + triggerName = "test-trigger" + eventTypeName = "test-eventtype" + subscriberName = "test-dumper" + waitTimeForBrokerPodsRunning = 30 * time.Second + ) + + t.Logf("Labeling Namespace %s", ns) + err := LabelNamespace(clients, t.Logf, map[string]string{"knative-eventing-injection": "enabled"}) + if err != nil { + t.Fatalf("Error labeling Namespace: %v", err) + } + t.Logf("Namespace %s labeled", ns) + + broker := test.NewBrokerBuilder(brokerName, ns). + IngressPolicy(fixture.ingressPolicy). + Build() + t.Logf("Creating and waiting for Broker %s ready", broker.Name) + err = WithBrokerReady(clients, broker, t.Logf, cleaner) + if err != nil { + t.Fatalf("Error creating and waiting for Broker ready: %v", err) + } + brokerUrl := fmt.Sprintf("http://%s", broker.Status.Address.Hostname) + t.Logf("Broker created and ready: %q", brokerUrl) + + t.Logf("Creating Subscriber Pod and Service") + selector := map[string]string{"e2etest": string(uuid.NewUUID())} + subscriberPod := test.EventLoggerPod(subscriberName, ns, selector) + subscriberSvc := test.Service(subscriberName, ns, selector) + subscriberPod, err = CreatePodAndServiceReady(clients, subscriberPod, subscriberSvc, ns, t.Logf, cleaner) + if err != nil { + t.Fatalf("Failed to create Subscriber Pod and Service, and get them ready: %v", err) + } + t.Logf("Subscriber Pod and Service created and ready") + + trigger := test.NewTriggerBuilder(triggerName, ns). + Broker(broker.Name). + SubscriberSvc(subscriberSvc.Name). + Build() + t.Logf("Creating and waiting for Trigger %s ready", trigger.Name) + err = WithTriggerReady(clients, trigger, t.Logf, cleaner) + if err != nil { + t.Fatalf("Error creating and waiting for Trigger ready: %v", err) + } + t.Logf("Trigger created and ready") + + eventType := test.NewEventTypeBuilder(eventTypeName, ns). + Broker(brokerName). + // use the default values for source, type and schema. + Build() + if fixture.preRegisterEvent { + t.Logf("Creating and waiting for EventType %s ready", eventType.Name) + err = WithEventTypeReady(clients, eventType, t.Logf, cleaner) + if err != nil { + t.Fatalf("Error creating and waiting for EventType ready: %v", err) + } + t.Logf("EventType created and ready") + } + + // We notice some crashLoopBacks in the Broker's filter and ingress pod creation. + // We then delay the creation of the sender pod in order not to miss the event. + t.Logf("Waiting for Broker's filter and ingress POD to become running") + time.Sleep(waitTimeForBrokerPodsRunning) + + body := fmt.Sprintf("Registry %s", uuid.NewUUID()) + cloudEvent := &test.CloudEvent{ + Source: test.CloudEventDefaultSource, + Type: test.CloudEventDefaultType, + Data: fmt.Sprintf(`{"msg":%q}`, body), + } + t.Logf("Creating Sender Pod") + senderPod := test.EventSenderPod("sender", ns, brokerUrl, cloudEvent) + if err := CreatePod(clients, senderPod, t.Logf, cleaner); err != nil { + t.Fatalf("Error creating event sender Pod: %v", err) + } + t.Logf("Sender Pod created. Waiting for it to be running") + if err := pkgTest.WaitForAllPodsRunning(clients.Kube, ns); err != nil { + t.Fatalf("Error waiting for Sender Pod to become running: %v", err) + } + t.Logf("Sender Pod running") + + if fixture.wantEventDelivered { + t.Logf("Verifying Event delivered") + if err := WaitForLogContents(clients, t.Logf, subscriberName, subscriberPod.Spec.Containers[0].Name, ns, []string{body}); err != nil { + t.Fatalf("Event not found in logs of Subscriber Pod %q: %v", subscriberName, err) + } + } else { + t.Logf("Verifying Event not delivered") + found, err := FindAnyLogContents(clients, t.Logf, subscriberName, subscriberPod.Spec.Containers[0].Name, ns, []string{body}) + if err != nil { + t.Fatalf("Failed querying to find log contents in Subscriber Pod %q: %v", subscriberName, err) + } + if found { + t.Fatalf("Unexpected event found in logs of Subscriber Pod %q", subscriberName) + } + } + + // As the EventType might have been auto-generated, we cannot query for the particular EventType + // with the name given by the constant eventTypeName. We just query for all of them, and see if all are ready. + err = WaitForAllEventTypesReady(clients, t.Logf, ns) + if fixture.wantEventRegistered { + t.Logf("Verifying Event registered") + if err != nil { + t.Fatalf("EventType %q not ready: %v", eventType.Name, err) + } + } else { + t.Logf("Verifying Event not registered") + if err == nil { + t.Fatalf("EventType %q registered and ready, but expected not to be", eventType.Name) + } + } +} diff --git a/test/states.go b/test/states.go index 1ff898b05f4..9deaf2d3d6d 100644 --- a/test/states.go +++ b/test/states.go @@ -46,6 +46,12 @@ func IsTriggerReady(t *eventingv1alpha1.Trigger) (bool, error) { return t.Status.IsReady(), nil } +// IsEventTypeReady will check the status conditions of the EventType and +// return true if the EventType is ready. +func IsEventTypeReady(et *eventingv1alpha1.EventType) (bool, error) { + return et.Status.IsReady(), nil +} + // TriggersReady will check the status conditions of the trigger list and return true // if all triggers are Ready. func TriggersReady(triggerList *eventingv1alpha1.TriggerList) (bool, error) { @@ -62,6 +68,22 @@ func TriggersReady(triggerList *eventingv1alpha1.TriggerList) (bool, error) { return true, nil } +// EventTypesReady will check the status conditions of the EventTypeList and return true +// if all EventTypes are Ready. +func EventTypesReady(eventTypeList *eventingv1alpha1.EventTypeList) (bool, error) { + var names []string + for _, t := range eventTypeList.Items { + names = append(names, t.Name) + } + log.Printf("Checking event types: %v", names) + for _, eventType := range eventTypeList.Items { + if !eventType.Status.IsReady() { + return false, nil + } + } + return true, nil +} + // PodsRunning will check the status conditions of the pod list and return true // if all pods are Running. func PodsRunning(podList *corev1.PodList) (bool, error) { From f0ce51178c22d79ac12c63875e08fd1f46686ebd Mon Sep 17 00:00:00 2001 From: nachocano Date: Wed, 10 Apr 2019 15:23:16 -0700 Subject: [PATCH 202/221] Updating deepcopy --- pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go | 8 ++------ .../externalversions/eventing/v1alpha1/eventtype.go | 6 +++--- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go index c072b61948f..2b5b2542ced 100644 --- a/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go @@ -98,12 +98,8 @@ func (in *BrokerSpec) DeepCopyInto(out *BrokerSpec) { } if in.IngressPolicy != nil { in, out := &in.IngressPolicy, &out.IngressPolicy - if *in == nil { - *out = nil - } else { - *out = new(IngressPolicySpec) - **out = **in - } + *out = new(IngressPolicySpec) + **out = **in } return } diff --git a/pkg/client/informers/externalversions/eventing/v1alpha1/eventtype.go b/pkg/client/informers/externalversions/eventing/v1alpha1/eventtype.go index 9e62ba5e723..b8c7bcef898 100644 --- a/pkg/client/informers/externalversions/eventing/v1alpha1/eventtype.go +++ b/pkg/client/informers/externalversions/eventing/v1alpha1/eventtype.go @@ -21,7 +21,7 @@ package v1alpha1 import ( time "time" - eventing_v1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" + eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" versioned "github.com/knative/eventing/pkg/client/clientset/versioned" internalinterfaces "github.com/knative/eventing/pkg/client/informers/externalversions/internalinterfaces" v1alpha1 "github.com/knative/eventing/pkg/client/listers/eventing/v1alpha1" @@ -70,7 +70,7 @@ func NewFilteredEventTypeInformer(client versioned.Interface, namespace string, return client.EventingV1alpha1().EventTypes(namespace).Watch(options) }, }, - &eventing_v1alpha1.EventType{}, + &eventingv1alpha1.EventType{}, resyncPeriod, indexers, ) @@ -81,7 +81,7 @@ func (f *eventTypeInformer) defaultInformer(client versioned.Interface, resyncPe } func (f *eventTypeInformer) Informer() cache.SharedIndexInformer { - return f.factory.InformerFor(&eventing_v1alpha1.EventType{}, f.defaultInformer) + return f.factory.InformerFor(&eventingv1alpha1.EventType{}, f.defaultInformer) } func (f *eventTypeInformer) Lister() v1alpha1.EventTypeLister { From d341ab24081b8dc3d8bb7fef3886e1f66c38b834 Mon Sep 17 00:00:00 2001 From: nachocano Date: Wed, 10 Apr 2019 16:10:40 -0700 Subject: [PATCH 203/221] naming changes --- test/e2e/registry_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/e2e/registry_test.go b/test/e2e/registry_test.go index a70d0054011..f012d1a82b5 100644 --- a/test/e2e/registry_test.go +++ b/test/e2e/registry_test.go @@ -37,7 +37,7 @@ type testFixture struct { wantEventRegistered bool } -func TestRegistryBrokerAllowAny(t *testing.T) { +func TestRegistryBrokerAllowAnyAccept(t *testing.T) { fixture := &testFixture{ ingressPolicy: &v1alpha1.IngressPolicySpec{ AllowAny: true, @@ -47,7 +47,7 @@ func TestRegistryBrokerAllowAny(t *testing.T) { Registry(t, fixture) } -func TestRegistryBrokerAllowRegisteredAndEventPreRegistered(t *testing.T) { +func TestRegistryBrokerAllowRegisteredAccept(t *testing.T) { fixture := &testFixture{ ingressPolicy: &v1alpha1.IngressPolicySpec{ AllowAny: false, @@ -59,7 +59,7 @@ func TestRegistryBrokerAllowRegisteredAndEventPreRegistered(t *testing.T) { Registry(t, fixture) } -func TestRegistryBrokerAllowRegisteredAndEventNotPreRegistered(t *testing.T) { +func TestRegistryBrokerAllowRegisteredNotAccept(t *testing.T) { fixture := &testFixture{ ingressPolicy: &v1alpha1.IngressPolicySpec{ AllowAny: false, @@ -68,7 +68,7 @@ func TestRegistryBrokerAllowRegisteredAndEventNotPreRegistered(t *testing.T) { Registry(t, fixture) } -func TestRegistryBrokerAutoAdd(t *testing.T) { +func TestRegistryBrokerAutoAddAccept(t *testing.T) { fixture := &testFixture{ ingressPolicy: &v1alpha1.IngressPolicySpec{ AutoAdd: true, From 06f98cf3764d86ab9bd125611b7145e418430400 Mon Sep 17 00:00:00 2001 From: nachocano Date: Wed, 10 Apr 2019 16:51:34 -0700 Subject: [PATCH 204/221] disabling registry test to see if this is causing problems --- test/e2e/registry_test.go | 60 +++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/test/e2e/registry_test.go b/test/e2e/registry_test.go index f012d1a82b5..b485338c9fa 100644 --- a/test/e2e/registry_test.go +++ b/test/e2e/registry_test.go @@ -38,45 +38,45 @@ type testFixture struct { } func TestRegistryBrokerAllowAnyAccept(t *testing.T) { - fixture := &testFixture{ - ingressPolicy: &v1alpha1.IngressPolicySpec{ - AllowAny: true, - }, - wantEventDelivered: true, - } - Registry(t, fixture) + //fixture := &testFixture{ + // ingressPolicy: &v1alpha1.IngressPolicySpec{ + // AllowAny: true, + // }, + // wantEventDelivered: true, + //} + //Registry(t, fixture) } func TestRegistryBrokerAllowRegisteredAccept(t *testing.T) { - fixture := &testFixture{ - ingressPolicy: &v1alpha1.IngressPolicySpec{ - AllowAny: false, - }, - preRegisterEvent: true, - wantEventDelivered: true, - wantEventRegistered: true, - } - Registry(t, fixture) + //fixture := &testFixture{ + // ingressPolicy: &v1alpha1.IngressPolicySpec{ + // AllowAny: false, + // }, + // preRegisterEvent: true, + // wantEventDelivered: true, + // wantEventRegistered: true, + //} + //Registry(t, fixture) } func TestRegistryBrokerAllowRegisteredNotAccept(t *testing.T) { - fixture := &testFixture{ - ingressPolicy: &v1alpha1.IngressPolicySpec{ - AllowAny: false, - }, - } - Registry(t, fixture) + //fixture := &testFixture{ + // ingressPolicy: &v1alpha1.IngressPolicySpec{ + // AllowAny: false, + // }, + //} + //Registry(t, fixture) } func TestRegistryBrokerAutoAddAccept(t *testing.T) { - fixture := &testFixture{ - ingressPolicy: &v1alpha1.IngressPolicySpec{ - AutoAdd: true, - }, - wantEventDelivered: true, - wantEventRegistered: true, - } - Registry(t, fixture) + //fixture := &testFixture{ + // ingressPolicy: &v1alpha1.IngressPolicySpec{ + // AutoAdd: true, + // }, + // wantEventDelivered: true, + // wantEventRegistered: true, + //} + //Registry(t, fixture) } func Registry(t *testing.T, fixture *testFixture) { From 00cd8e24f68c580a416c0007f064019c9ea7827b Mon Sep 17 00:00:00 2001 From: nachocano Date: Thu, 11 Apr 2019 13:31:53 -0700 Subject: [PATCH 205/221] re-enabling these guys again --- test/e2e/registry_test.go | 60 +++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/test/e2e/registry_test.go b/test/e2e/registry_test.go index b485338c9fa..f012d1a82b5 100644 --- a/test/e2e/registry_test.go +++ b/test/e2e/registry_test.go @@ -38,45 +38,45 @@ type testFixture struct { } func TestRegistryBrokerAllowAnyAccept(t *testing.T) { - //fixture := &testFixture{ - // ingressPolicy: &v1alpha1.IngressPolicySpec{ - // AllowAny: true, - // }, - // wantEventDelivered: true, - //} - //Registry(t, fixture) + fixture := &testFixture{ + ingressPolicy: &v1alpha1.IngressPolicySpec{ + AllowAny: true, + }, + wantEventDelivered: true, + } + Registry(t, fixture) } func TestRegistryBrokerAllowRegisteredAccept(t *testing.T) { - //fixture := &testFixture{ - // ingressPolicy: &v1alpha1.IngressPolicySpec{ - // AllowAny: false, - // }, - // preRegisterEvent: true, - // wantEventDelivered: true, - // wantEventRegistered: true, - //} - //Registry(t, fixture) + fixture := &testFixture{ + ingressPolicy: &v1alpha1.IngressPolicySpec{ + AllowAny: false, + }, + preRegisterEvent: true, + wantEventDelivered: true, + wantEventRegistered: true, + } + Registry(t, fixture) } func TestRegistryBrokerAllowRegisteredNotAccept(t *testing.T) { - //fixture := &testFixture{ - // ingressPolicy: &v1alpha1.IngressPolicySpec{ - // AllowAny: false, - // }, - //} - //Registry(t, fixture) + fixture := &testFixture{ + ingressPolicy: &v1alpha1.IngressPolicySpec{ + AllowAny: false, + }, + } + Registry(t, fixture) } func TestRegistryBrokerAutoAddAccept(t *testing.T) { - //fixture := &testFixture{ - // ingressPolicy: &v1alpha1.IngressPolicySpec{ - // AutoAdd: true, - // }, - // wantEventDelivered: true, - // wantEventRegistered: true, - //} - //Registry(t, fixture) + fixture := &testFixture{ + ingressPolicy: &v1alpha1.IngressPolicySpec{ + AutoAdd: true, + }, + wantEventDelivered: true, + wantEventRegistered: true, + } + Registry(t, fixture) } func Registry(t *testing.T, fixture *testFixture) { From b3247943932282b2d71d732fa25cb6868af54fc4 Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Wed, 24 Apr 2019 16:22:56 -0700 Subject: [PATCH 206/221] Missing files --- .../x/oauth2/google/appengine_gen1.go | 77 +++++++++++++++++++ .../x/oauth2/google/appengine_gen2_flex.go | 27 +++++++ vendor/golang.org/x/oauth2/google/doc.go | 40 ++++++++++ 3 files changed, 144 insertions(+) create mode 100644 vendor/golang.org/x/oauth2/google/appengine_gen1.go create mode 100644 vendor/golang.org/x/oauth2/google/appengine_gen2_flex.go create mode 100644 vendor/golang.org/x/oauth2/google/doc.go diff --git a/vendor/golang.org/x/oauth2/google/appengine_gen1.go b/vendor/golang.org/x/oauth2/google/appengine_gen1.go new file mode 100644 index 00000000000..83dacac320a --- /dev/null +++ b/vendor/golang.org/x/oauth2/google/appengine_gen1.go @@ -0,0 +1,77 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build appengine + +// This file applies to App Engine first generation runtimes (<= Go 1.9). + +package google + +import ( + "context" + "sort" + "strings" + "sync" + + "golang.org/x/oauth2" + "google.golang.org/appengine" +) + +func init() { + appengineTokenFunc = appengine.AccessToken + appengineAppIDFunc = appengine.AppID +} + +// See comment on AppEngineTokenSource in appengine.go. +func appEngineTokenSource(ctx context.Context, scope ...string) oauth2.TokenSource { + scopes := append([]string{}, scope...) + sort.Strings(scopes) + return &gaeTokenSource{ + ctx: ctx, + scopes: scopes, + key: strings.Join(scopes, " "), + } +} + +// aeTokens helps the fetched tokens to be reused until their expiration. +var ( + aeTokensMu sync.Mutex + aeTokens = make(map[string]*tokenLock) // key is space-separated scopes +) + +type tokenLock struct { + mu sync.Mutex // guards t; held while fetching or updating t + t *oauth2.Token +} + +type gaeTokenSource struct { + ctx context.Context + scopes []string + key string // to aeTokens map; space-separated scopes +} + +func (ts *gaeTokenSource) Token() (*oauth2.Token, error) { + aeTokensMu.Lock() + tok, ok := aeTokens[ts.key] + if !ok { + tok = &tokenLock{} + aeTokens[ts.key] = tok + } + aeTokensMu.Unlock() + + tok.mu.Lock() + defer tok.mu.Unlock() + if tok.t.Valid() { + return tok.t, nil + } + access, exp, err := appengineTokenFunc(ts.ctx, ts.scopes...) + if err != nil { + return nil, err + } + tok.t = &oauth2.Token{ + AccessToken: access, + Expiry: exp, + } + return tok.t, nil +} diff --git a/vendor/golang.org/x/oauth2/google/appengine_gen2_flex.go b/vendor/golang.org/x/oauth2/google/appengine_gen2_flex.go new file mode 100644 index 00000000000..04c2c2216af --- /dev/null +++ b/vendor/golang.org/x/oauth2/google/appengine_gen2_flex.go @@ -0,0 +1,27 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !appengine + +// This file applies to App Engine second generation runtimes (>= Go 1.11) and App Engine flexible. + +package google + +import ( + "context" + "log" + "sync" + + "golang.org/x/oauth2" +) + +var logOnce sync.Once // only spam about deprecation once + +// See comment on AppEngineTokenSource in appengine.go. +func appEngineTokenSource(ctx context.Context, scope ...string) oauth2.TokenSource { + logOnce.Do(func() { + log.Print("google: AppEngineTokenSource is deprecated on App Engine standard second generation runtimes (>= Go 1.11) and App Engine flexible. Please use DefaultTokenSource or ComputeTokenSource.") + }) + return ComputeTokenSource("") +} diff --git a/vendor/golang.org/x/oauth2/google/doc.go b/vendor/golang.org/x/oauth2/google/doc.go new file mode 100644 index 00000000000..73be629033d --- /dev/null +++ b/vendor/golang.org/x/oauth2/google/doc.go @@ -0,0 +1,40 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package google provides support for making OAuth2 authorized and authenticated +// HTTP requests to Google APIs. It supports the Web server flow, client-side +// credentials, service accounts, Google Compute Engine service accounts, and Google +// App Engine service accounts. +// +// A brief overview of the package follows. For more information, please read +// https://developers.google.com/accounts/docs/OAuth2 +// and +// https://developers.google.com/accounts/docs/application-default-credentials. +// +// OAuth2 Configs +// +// Two functions in this package return golang.org/x/oauth2.Config values from Google credential +// data. Google supports two JSON formats for OAuth2 credentials: one is handled by ConfigFromJSON, +// the other by JWTConfigFromJSON. The returned Config can be used to obtain a TokenSource or +// create an http.Client. +// +// +// Credentials +// +// The Credentials type represents Google credentials, including Application Default +// Credentials. +// +// Use FindDefaultCredentials to obtain Application Default Credentials. +// FindDefaultCredentials looks in some well-known places for a credentials file, and +// will call AppEngineTokenSource or ComputeTokenSource as needed. +// +// DefaultClient and DefaultTokenSource are convenience methods. They first call FindDefaultCredentials, +// then use the credentials to construct an http.Client or an oauth2.TokenSource. +// +// Use CredentialsFromJSON to obtain credentials from either of the two JSON formats +// described in OAuth2 Configs, above. The TokenSource in the returned value is the +// same as the one obtained from the oauth2.Config returned from ConfigFromJSON or +// JWTConfigFromJSON, but the Credentials may contain additional information +// that is useful is some circumstances. +package google // import "golang.org/x/oauth2/google" From 82f3921ed0caeafe00a6e6dbeb627f0861e5498e Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Thu, 25 Apr 2019 09:25:11 -0700 Subject: [PATCH 207/221] adding description --- pkg/apis/eventing/v1alpha1/broker_defaults.go | 2 +- .../eventing/v1alpha1/broker_defaults_test.go | 23 +------- pkg/apis/eventing/v1alpha1/broker_types.go | 3 +- .../eventing/v1alpha1/eventtype_lifecycle.go | 58 +++++++++++++++++++ ...es_test.go => eventtype_lifecycle_test.go} | 0 pkg/apis/eventing/v1alpha1/eventtype_types.go | 48 +++------------ 6 files changed, 69 insertions(+), 65 deletions(-) create mode 100644 pkg/apis/eventing/v1alpha1/eventtype_lifecycle.go rename pkg/apis/eventing/v1alpha1/{eventtype_types_test.go => eventtype_lifecycle_test.go} (100%) diff --git a/pkg/apis/eventing/v1alpha1/broker_defaults.go b/pkg/apis/eventing/v1alpha1/broker_defaults.go index 2cada7abaa0..388ee3e7aec 100644 --- a/pkg/apis/eventing/v1alpha1/broker_defaults.go +++ b/pkg/apis/eventing/v1alpha1/broker_defaults.go @@ -24,9 +24,9 @@ func (b *Broker) SetDefaults(ctx context.Context) { func (bs *BrokerSpec) SetDefaults(ctx context.Context) { if bs.IngressPolicy == nil { + // Setting as default to allow any event. bs.IngressPolicy = &IngressPolicySpec{ AllowAny: true, - AutoAdd: false, } } } diff --git a/pkg/apis/eventing/v1alpha1/broker_defaults_test.go b/pkg/apis/eventing/v1alpha1/broker_defaults_test.go index 7924457b1e3..dcee2377dee 100644 --- a/pkg/apis/eventing/v1alpha1/broker_defaults_test.go +++ b/pkg/apis/eventing/v1alpha1/broker_defaults_test.go @@ -34,24 +34,6 @@ func TestBrokerDefaults(t *testing.T) { Spec: BrokerSpec{ IngressPolicy: &IngressPolicySpec{ AllowAny: true, - AutoAdd: false, - }, - }, - }, - }, - "auto add not set": { - initial: Broker{ - Spec: BrokerSpec{ - IngressPolicy: &IngressPolicySpec{ - AllowAny: true, - }, - }, - }, - expected: Broker{ - Spec: BrokerSpec{ - IngressPolicy: &IngressPolicySpec{ - AllowAny: true, - AutoAdd: false, }, }, }, @@ -59,16 +41,13 @@ func TestBrokerDefaults(t *testing.T) { "allow any not set": { initial: Broker{ Spec: BrokerSpec{ - IngressPolicy: &IngressPolicySpec{ - AutoAdd: true, - }, + IngressPolicy: &IngressPolicySpec{}, }, }, expected: Broker{ Spec: BrokerSpec{ IngressPolicy: &IngressPolicySpec{ AllowAny: false, - AutoAdd: true, }, }, }, diff --git a/pkg/apis/eventing/v1alpha1/broker_types.go b/pkg/apis/eventing/v1alpha1/broker_types.go index cf39e6d5a57..12c8995aeab 100644 --- a/pkg/apis/eventing/v1alpha1/broker_types.go +++ b/pkg/apis/eventing/v1alpha1/broker_types.go @@ -56,13 +56,14 @@ type BrokerSpec struct { // +optional ChannelTemplate *ChannelSpec `json:"channelTemplate,omitempty"` + // IngressPolicy defines the Broker's policy regarding the events it can accept into the mesh or not. // +optional IngressPolicy *IngressPolicySpec `json:"ingressPolicy,omitempty"` } type IngressPolicySpec struct { + // AllowAny, if set to true accepts any message into the mesh. If set to false, only allows pre-registered events. AllowAny bool `json:"allowAny,omitempty"` - AutoAdd bool `json:"autoAdd,omitempty"` } // BrokerStatus represents the current state of a Broker. diff --git a/pkg/apis/eventing/v1alpha1/eventtype_lifecycle.go b/pkg/apis/eventing/v1alpha1/eventtype_lifecycle.go new file mode 100644 index 00000000000..5cef6862a6c --- /dev/null +++ b/pkg/apis/eventing/v1alpha1/eventtype_lifecycle.go @@ -0,0 +1,58 @@ +/* +Copyright 2019 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" + +var eventTypeCondSet = duckv1alpha1.NewLivingConditionSet(EventTypeConditionBrokerExists, EventTypeConditionBrokerReady) + +const ( + EventTypeConditionReady = duckv1alpha1.ConditionReady + EventTypeConditionBrokerExists duckv1alpha1.ConditionType = "BrokerExists" + EventTypeConditionBrokerReady duckv1alpha1.ConditionType = "BrokerReady" +) + +// GetCondition returns the condition currently associated with the given type, or nil. +func (et *EventTypeStatus) GetCondition(t duckv1alpha1.ConditionType) *duckv1alpha1.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() +} + +// 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) MarkBrokerReady() { + eventTypeCondSet.Manage(et).MarkTrue(EventTypeConditionBrokerReady) +} + +func (et *EventTypeStatus) MarkBrokerNotReady() { + eventTypeCondSet.Manage(et).MarkFalse(EventTypeConditionBrokerReady, "BrokerNotReady", "Broker is not ready") +} diff --git a/pkg/apis/eventing/v1alpha1/eventtype_types_test.go b/pkg/apis/eventing/v1alpha1/eventtype_lifecycle_test.go similarity index 100% rename from pkg/apis/eventing/v1alpha1/eventtype_types_test.go rename to pkg/apis/eventing/v1alpha1/eventtype_lifecycle_test.go diff --git a/pkg/apis/eventing/v1alpha1/eventtype_types.go b/pkg/apis/eventing/v1alpha1/eventtype_types.go index 6403aa09f79..f688c6ebba2 100644 --- a/pkg/apis/eventing/v1alpha1/eventtype_types.go +++ b/pkg/apis/eventing/v1alpha1/eventtype_types.go @@ -49,13 +49,18 @@ var _ runtime.Object = (*EventType)(nil) var _ webhook.GenericCRD = (*EventType)(nil) type EventTypeSpec struct { + // Type represents the CloudEvents type. It is authoritative. Type string `json:"type"` - // +optional + // Source is a valid URI, it represents the CloudEvents source. Source string `json:"source,omitempty"` + // Schema is a valid URI, it represents the CloudEvents schema attribute. + // It may be a JSON schema, a protobuf schema, etc. It is optional. // +optional Schema string `json:"schema,omitempty"` - + // Broker refers to the Broker that can provide the EventType. Broker string `json:"broker"` + // Description is an optional field used to describe the EventType, in any meaningful way. + Description string `json:description,omitempty` } // EventTypeStatus represents the current state of a EventType. @@ -66,45 +71,6 @@ type EventTypeStatus struct { duckv1alpha1.Status `json:",inline"` } -const ( - EventTypeConditionReady = duckv1alpha1.ConditionReady - EventTypeConditionBrokerExists duckv1alpha1.ConditionType = "BrokerExists" - EventTypeConditionBrokerReady duckv1alpha1.ConditionType = "BrokerReady" -) - -var eventTypeCondSet = duckv1alpha1.NewLivingConditionSet(EventTypeConditionBrokerExists, EventTypeConditionBrokerReady) - -// GetCondition returns the condition currently associated with the given type, or nil. -func (et *EventTypeStatus) GetCondition(t duckv1alpha1.ConditionType) *duckv1alpha1.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() -} - -// 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) MarkBrokerReady() { - eventTypeCondSet.Manage(et).MarkTrue(EventTypeConditionBrokerReady) -} - -func (et *EventTypeStatus) MarkBrokerNotReady() { - eventTypeCondSet.Manage(et).MarkFalse(EventTypeConditionBrokerReady, "BrokerNotReady", "Broker is not ready") -} - // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // EventTypeList is a collection of EventTypes. From 1a4ab08f7a195eaa55c8440a39876a175adce36e Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Thu, 25 Apr 2019 09:30:40 -0700 Subject: [PATCH 208/221] removing autoAdd --- cmd/broker/ingress/main.go | 4 -- pkg/broker/ingress.go | 45 +++---------------- .../v1alpha1/broker/resources/ingress.go | 4 -- 3 files changed, 5 insertions(+), 48 deletions(-) diff --git a/cmd/broker/ingress/main.go b/cmd/broker/ingress/main.go index 3050c6da1d6..726d75dda16 100644 --- a/cmd/broker/ingress/main.go +++ b/cmd/broker/ingress/main.go @@ -70,9 +70,6 @@ type envConfig struct { // To indicate whether the ingress should allow any event. AllowAny bool `envconfig:"ALLOW_ANY" required:"true"` - - // To indicate whether the ingress should auto-register unknown events. - AutoAdd bool `envconfig:"AUTO_ADD" required:"true"` } func main() { @@ -114,7 +111,6 @@ func main() { policySpec := &eventingv1alpha1.IngressPolicySpec{ AllowAny: env.AllowAny, - AutoAdd: env.AutoAdd, } ingressPolicy := broker.NewPolicy(logger, client, policySpec, namespace, brokerName, true) diff --git a/pkg/broker/ingress.go b/pkg/broker/ingress.go index 357011f285d..973de60fa96 100644 --- a/pkg/broker/ingress.go +++ b/pkg/broker/ingress.go @@ -62,48 +62,13 @@ func NewPolicy(logger *zap.Logger, client client.Client, spec *eventingv1alpha1. // AllowEvent filters events based on the configured policy. func (p *IngressPolicy) AllowEvent(ctx context.Context, event cloudevents.Event) bool { - // 1. If autoAdd is set to true, then the event is accepted. In case it wasn't seen before, it is added to the Broker's registry. + // 1. If allowAny is set to true, then all events are allowed to enter the mesh. // 2. If allowAny is set to false, then the event is only accepted if it's already in the Broker's registry. - // 3. If allowAny is set to true, then all events are allowed to enter the mesh. - if p.spec.AutoAdd { - return p.autoAdd(ctx, event) + if p.spec.AllowAny { + p.logger.Debugf("EventType %q received, Accept", event.Type()) + return true } - if !p.spec.AllowAny { - return p.isRegistered(ctx, event) - } - p.logger.Debugf("EventType %q received, Accept", event.Type()) - return true -} - -// autoAdd attempts to add the EventType corresponding to the CloudEvent if it's not available in the Registry. -// It always returns true. -func (p *IngressPolicy) autoAdd(ctx context.Context, event cloudevents.Event) bool { - addFunc := func(ctx context.Context) { - _, err := p.getEventType(ctx, event) - if k8serrors.IsNotFound(err) { - p.logger.Debugf("EventType %q not found: Registering", event.Type()) - eventType := p.makeEventType(event) - err := p.client.Create(ctx, eventType) - if err != nil { - p.logger.Errorf("Error registering EventType %q: %v", event.Type(), err) - } else { - p.logger.Debugf("EventType %q Registered", event.Type()) - } - } else if err != nil { - p.logger.Errorf("Error retrieving EventType %q: %v", event.Type(), err) - } - } - if p.async { - // TODO do this in a working queue - // TODO should run some background task to dedupe EventTypes within Brokers. - // Do not use the previous context as it seems that it can be canceled before - // this routine executes. - go addFunc(context.TODO()) - } else { - addFunc(ctx) - } - p.logger.Debugf("EventType %q received, Accept", event.Type()) - return true + return p.isRegistered(ctx, event) } // isRegistered returns whether the EventType corresponding to the CloudEvent is available in the Registry. diff --git a/pkg/reconciler/v1alpha1/broker/resources/ingress.go b/pkg/reconciler/v1alpha1/broker/resources/ingress.go index 7be175a266a..5830208693f 100644 --- a/pkg/reconciler/v1alpha1/broker/resources/ingress.go +++ b/pkg/reconciler/v1alpha1/broker/resources/ingress.go @@ -84,10 +84,6 @@ func MakeIngress(args *IngressArgs) *appsv1.Deployment { Name: "BROKER", Value: args.Broker.Name, }, - { - Name: "AUTO_ADD", - Value: strconv.FormatBool(args.Broker.Spec.IngressPolicy.AutoAdd), - }, { Name: "ALLOW_ANY", Value: strconv.FormatBool(args.Broker.Spec.IngressPolicy.AllowAny), From f0df342eee8ddb3443ed7789f7756bdbc17e0846 Mon Sep 17 00:00:00 2001 From: nachocano Date: Thu, 25 Apr 2019 10:39:40 -0700 Subject: [PATCH 209/221] some updates, still broken --- config/200-broker-clusterrole.yaml | 1 - config/300-eventtype.yaml | 3 + docs/registry/README.md | 391 --------------------- docs/registry/example_broker_policies.yaml | 13 - docs/registry/example_eventtype.yaml | 19 +- pkg/broker/context.go | 9 +- pkg/broker/ingress.go | 46 +-- pkg/broker/ingress_test.go | 74 ---- pkg/broker/receiver.go | 13 +- 9 files changed, 21 insertions(+), 548 deletions(-) delete mode 100644 docs/registry/README.md diff --git a/config/200-broker-clusterrole.yaml b/config/200-broker-clusterrole.yaml index f5d6595029f..02dc2f7ed63 100644 --- a/config/200-broker-clusterrole.yaml +++ b/config/200-broker-clusterrole.yaml @@ -43,4 +43,3 @@ rules: - get - list - watch - - create diff --git a/config/300-eventtype.yaml b/config/300-eventtype.yaml index ba1ebabe7b4..1b83fd8cd11 100644 --- a/config/300-eventtype.yaml +++ b/config/300-eventtype.yaml @@ -42,6 +42,9 @@ spec: - name: Broker type: string JSONPath: ".spec.broker" + - name: Description + type: string + JSONPath: ".spec.description" - name: Ready type: string JSONPath: ".status.conditions[?(@.type==\"Ready\")].status" diff --git a/docs/registry/README.md b/docs/registry/README.md deleted file mode 100644 index e663ccb86a5..00000000000 --- a/docs/registry/README.md +++ /dev/null @@ -1,391 +0,0 @@ -# Registry Proposal - -## Problem - -As an `Event Consumer` I want to be able to discover the different event types that I can consume -from the different Brokers, without resorting to any OOB mechanism. -This is also known as the `discoverability` use case, and is the main focus of this proposal. - -## Objective - -Design an **initial** version of the **Registry** for the **MVP** that can support discoverability of -the different event types that can be consumed from the eventing mesh. For details on the different user stories -that this proposal touches, please refer to the -[User stories and personas for Knative eventing](https://docs.google.com/document/d/15uhyqQvaomxRX2u8s0i6CNhA86BQTNztkdsLUnPmvv4/edit?usp=sharing) document. -Note that this proposal targets the cases were the Broker/Trigger model is used. - -#### Out of scope - -- Registry to Registry communication. This doesn't seem needed for an MVP. -- Security-related matters. Those are handled offline by the `Cluster Configurator`, e.g., the `Cluster Configurator` -takes care of setting up Secrets for connecting to a GitHub repo, and so on. -- Registry synchronization with `Event Producers`. We assume that if new GitHub events are created by -GitHub after our cluster has been configured (i.e., our GitHub CRD Source installed) and the appropriate webhooks -have been created, we will need to create new webhooks (and update the GitHub CRD Source) if we want to listen for -those new events. Until doing so, those new events shouldn't be listed in the Registry. -Such task will again be in charge of the `Cluster Configurator`. - -## Requirements - -Our design revolves around the following core requirements: - -1. We should have a Registry per namespace to enforce isolation. -2. The Registry should contain the event types that can be consumed from -the eventing mesh in order to support the `discoverability` use case. -If an event type is not ready for consumption, we should explicitly indicate so (e.g., if the Broker -is not ready). -3. The event types stored in the Registry should contain all the required information -for a consumer to create a Trigger without resorting to some other OOB mechanism. - - -## Proposed Ideas - -### EventType CRD - -We propose introducing a namespaced-EventType CRD. Here is an example of how a CR would look like: - -```yaml -apiVersion: eventing.knative.dev/v1alpha1 -kind: EventType -metadata: - name: repopush - namespace: default -spec: - type: repo:push - source: my-user/my-repo - schema: /my-schema - broker: default -``` - -- The `name` of the EventType is advisory, non-authoritative. Given that CloudEvents types can -contain characters that may not comply with Kubernetes naming conventions, we will (slightly) -modify those names to make them K8s-compliant, whenever we need to generate them. - -- `type` is authoritative. This refers to the CloudEvent type as it enters into the eventing mesh. - -- `source`: an identifier of where we receive the event from. This might not necessarily be the CloudEvent source -attribute. - -If we have control over the entity emitting the CloudEvent, as is the case of many of our receive adaptors, -then we propose to add a CloudEvent custom extension (e.g., from) with this information, to ease the creation of filters -on Triggers later on. -As the CloudEvent source attribute is somewhat useless (e.g., github pull requests are populated with `https://github.com///pull/`), -there is no way of doing exact matching of CloudEvent sources on Triggers. Thus, we propose adding this custom extension -to CloudEvents whenever we can. If the extension is not present, then we fallback to the CloudEvent source. -Note that when we start supporting more advanced filtering mechanisms on Triggers, we might not need this. Further, with the -addition of `subject`, the meaning of the CloudEvent source might change, and we might be better off then. This needs further -discussion. - - -- `schema` is a URI with the EventType schema. It may be a JSON schema, a protobuf schema, etc. It is optional. - -- `broker` refers to the Broker that can provide the EventType. - -### Typical Flow - -`1.` A `Cluster Configurator` configures the cluster in a way that allows the population of EventTypes in the Registry. -We foresee the following three ways of populating the Registry so far: - -`1.1` Event Source CR installation - -Upon installation of an Event Source CR by a `Cluster Configurator`, the Source will register its EventTypes. - -Example: - -```yaml -apiVersion: sources.eventing.knative.dev/v1alpha1 -kind: GitHubSource -metadata: - name: github-source-sample - namespace: default -spec: - eventTypes: - - push - - pull_request - ownerAndRepository: my-other-user/my-other-repo - accessToken: - secretKeyRef: - name: github-secret - key: accessToken - secretToken: - secretKeyRef: - name: github-secret - key: secretToken - sink: - apiVersion: eventing.knative.dev/v1alpha1 - kind: Broker - name: default - -``` - -By applying the above file, two EventTypes will be registered, with types `dev.knative.source.github.push` and -`dev.knative.source.github.pull_request`, source `my-other-user/my-other-repo`, for the `default` Broker in the `default` - namespace, and with owner `github-source-sample`. This should be done by the Event Source controller, in this case, - the GitHubSource controller. - -Note that the `Cluster Configurator` is the person in charge of taking care of authentication-related matters. E.g., if a new `Event Consumer` -wants to listen for events from a different GitHub repo, the `Cluster Configurator` will take care of the necessary secrets generation, -and new Source instantiation. - -In YAML, the above EventTypes would look something like these: - -```yaml -apiVersion: eventing.knative.dev/v1alpha1 -kind: EventType -metadata: - generateName: dev.knative.source.github.push- - namespace: default - owner: # Owned by github-source-sample -spec: - type: dev.knative.source.github.push - source: my-other-user/my-other-repo - broker: default ---- -apiVersion: eventing.knative.dev/v1alpha1 -kind: EventType -metadata: - generateName: dev.knative.source.github.pullrequest- - namespace: default - owner: # Owned by github-source-sample -spec: - type: dev.knative.source.github.pull_request - source: my-other-user/my-other-repo - broker: default -``` - -Two things to notice: -- We generate the names by stripping invalid characters from the original type (e.g., `_`) -- The `spec.type` adds the prefix `dev.knative.source.github.` This is a **separate discussion** on whether we should -change the (GitHub) types or not. - -`1.2.` Manual Registration - -The `Cluster Configurator` manually `kubectl applies` an EventType CR. - -Example: - -```yaml -apiVersion: eventing.knative.dev/v1alpha1 -kind: EventType -metadata: - name: repofork - namespace: default -spec: - type: repo:fork - source: my-other-user/my-other-repo - broker: dev -``` - -This would register the EventType named `repofork` with type `repo:fork`, source `my-other-user/my-other-repo` -in the `dev` Broker of the `default` namespace. - -As under the hood, `kubeclt apply` just makes a REST call to the API server with the appropriate RBAC permissions, -the `Cluster Configurator` can give EventType `create` permissions to trusted parties, so that they can register -their EventTypes. - - -`1.3` Broker Auto Registration Policy - -The `Cluster Configurator` configures the Broker ingress policy to allow auto-registration of EventTypes. -Upon arrival of a non-registered EventType to the Broker ingress, the Broker will then create that type. -Note that the creation of the EventType is done asynchronously, i.e., the CloudEvent is accepted and sent -to the appropriate Trigger(s) in parallel of the EventType creation. If the creation fails, on a subsequent arrival -there will be a new creation attempt. - -Although sub-optimal (as `Event Consumers` find out about EventTypes upon first arrival), we believe this mechanism (or something similar) -is needed for Sources where the `Cluster Configurator` does not know in advance the EventTypes they can produce (e.g., a ContainerSource). - -Example: - -Set up a Broker with `autoAdd` enabled. - -```yaml -apiVersion: eventing.knative.dev/v1alpha1 -kind: Broker -metadata: - name: auto-add-demo -spec: - ingressPolicy: - autoAdd: true -``` - -Now if someone emits a non-registered event (e.g., `dev.knative.foo.bar`) -into the Broker `auto-add-demo`, an EventType will be created upon the event arrival. -Note that the Broker's address is well-known, it will always be -`-broker..svc.`. In this case case, it is -`auto-add-demo-broker.default.svc.cluster.local`. - -We can send the event manually. While SSHed into a `Pod` with the Istio sidecar, run: - -```shell -curl -v "http://auto-add-demo-broker.default.svc.cluster.local/" \ - -X POST \ - -H "X-B3-Flags: 1" \ - -H "CE-CloudEventsVersion: 0.1" \ - -H "CE-EventType: dev.knative.foo.bar" \ - -H "CE-EventTime: 2018-04-05T03:56:24Z" \ - -H "CE-EventID: 45a8b444-3213-4758-be3f-540bf93f85ff" \ - -H "CE-Source: dev.knative.example" \ - -H 'Content-Type: application/json' \ - -d '{ "much": "wow" }' -``` - -The Broker `auto-add-demo` will then create the EventType with type `dev.knative.foo.bar` in the Registry. -In YAML, the EventType would look something like these: - -```yaml -apiVersion: eventing.knative.dev/v1alpha1 -kind: EventType -metadata: - generateName: dev.knative.foo.bar- - namespace: default - owner: # Owned by auto-add-demo? -spec: - type: dev.knative.foo.bar - source: dev.knative.example - broker: auto-add-demo -``` - -`2.` An `Event Consumer` checks the Registry to see what EventTypes it can consume from the mesh. - -Example: - -`$ kubectl get eventtypes -n default` - -``` -NAME TYPE SOURCE SCHEMA BROKER READY REASON -dev.knative.foo.bar-55wcn dev.knative.foo.bar dev.knative.example auto-add-demo True -repofork repo:fork my-other-user/my-other-repo dev False BrokerIsNotReady -repopush repo:push my-other-user/my-other-repo /my-schema default True -dev.knative.source.github.push-34cnb dev.knative.source.github.push my-user/my-repo default True -dev.knative.source.github.pullrequest-86jhv dev.knative.source.github.pull_request my-user/my-repo default True -``` - -`3.` The `Event Consumer` creates a Trigger to listen to an EventType in the Registry. - -Example: - -```yaml -apiVersion: eventing.knative.dev/v1alpha1 -kind: Trigger -metadata: - name: my-service-trigger - namespace: default -spec: - filter: - sourceAndType: - type: dev.knative.foo.bar - source: dev.knative.example - subscriber: - ref: - apiVersion: serving.knative.dev/v1alpha1 - kind: Service - name: my-service -``` - -### Broker Ingress Policies - -We briefly mentioned configuring an ingress policy in the Broker so that it can auto-register EventTypes. -In order to support that, we propose adding an `ingressPolicy` field to the Broker's spec CRD. - -Below are two CR examples with Brokers configured using different policies. Note that the fields of -`ingressPolicy` might change (e.g., `ingressPolicy` might just end up being a string). -We are omitting Broker's fields irrelevant to this discussion. -Also note that such configuration is done by the `Cluster Configurator`. - -- Allow Registered - -By setting the ingress policy to not allow any, the Broker will accept only events with EventTypes in the Registry. - -```yaml -apiVersion: eventing.knative.dev/v1alpha1 -kind: Broker -metadata: - name: broker-allow-registered -spec: - ingressPolicy: - allowAny: false -``` - -- Auto Add - -By setting the ingress policy to auto add, the Broker will accept any event and will add its EventType -to the Registry (in case it is not present). - -```yaml -apiVersion: eventing.knative.dev/v1alpha1 -kind: Broker -metadata: - name: broker-auto-add -spec: - ingressPolicy: - autoAdd: true -``` - -By not specifying an ingress policy, we thought that the default behavior would be to accept any event, which is similar to `Auto Add` -but without registration of events. This needs further discussion. - -Note that more policies should probably need to be configured in the future, e.g., allow auto-registration of EventTypes received -from within the cluster (e.g., from a response of a Service running in the cluster) as opposed to external services, and so on. -We just enumerate two simple cases here. - -## FAQ - -Here is a list of frequently asked questions that may help clarify the scope of the Registry. - -- Is the Registry meant to be used just for creating Triggers or for also setting up Event Sources? - - It's mainly intended for helping the `Event Consumer` with the `discoverability` use case. Therefore, - it is meant for helping out creating Triggers. - -- If I have a simple use case where I'm just setting up an Event Source and my KnService is its Sink (i.e., no Triggers involved), -is there a need/use for the Registry? - - As stated before, this Registry proposal for the MVP helps creating Triggers, i.e., when you use the Broker/Trigger - model. As you can see in the EventType CRD, there is a mandatory `broker` field. If you are not sending events to a Broker, - then EventTypes won't be added to the Registry (at least in this proposal). - Implementation-wise, we can check whether the Source's sink kind is `Broker`, and if so, then register its EventTypes. - - -- Is the Registry meant to be used in a single-user environment where the same person is setting up both the Event Source and -the destination Sink? - - We believe is mainly intended for multi-user environment. A `Cluster Configurator` persona is in charge of setting up - the Sources, and `Event Consumers` are the ones that create the Triggers. Having said that, it can also be used in - a single-user environment, but the Registry might not add much value compared to what we have right now in terms of - `discoverability`, but it surely does in terms of, for example, `admission control`. - -- Does a user need to know which type of environment they're in before they should know if they should look at the Registry? -In other words, is a Registry always going to be there and if not under what conditions will it be? - - A Registry will always be there, i.e., `Event Consumers` will always be able to `kubectl get eventtypes -n `. - In case no CR Sources are pointing to Brokers, then the Registry will be empty. - -- Once an Event Source is created, how is a new one created with different auth in an env where the user is really just meant -to deal with Triggers? This may not be a Registry specific question but if one of the goals of the Registry is to make it -so that the user only deals with Triggers using the info in the Registry, I think this aspect comes into play. - - We believe the Event Source instantiation with different credentials should be handled by the `Cluster Configurer`. If the - `Cluster Configurer` persona happens to be the same person as the `Event Consumer` persona, then it will have to take care - of creating the Source. This is related to the question of a single-user, multi-user environment above. - -- I've heard conflicting messages around whether the Registry is just a list of Event Types or it will also be a list of -Event Sources so that the user doesn't need to query the CRDs to get the list. We need to be clear about this. - - The Registry is a list of EventTypes. Having said that, the `Event Consumer` could also (if it has the proper RBAC permissions) - list Event Sources (e.g., `kubectl get crds -l eventing.knative.dev/source=true`), but that list is not part of what we call - Registry here. The idea behind the fields in the EventType CRD is to have all the necessary information there in - order to create Triggers, thus, in most cases, the `Event Consumer` shouldn't have to list Sources. - -- I wonder if the Event Source populating the Registry should happen when the Event Source is loaded into the system, -meaning when the Event Source's CRD is installed (not when an instance of the CRD is created). - -The problem with that is that you don't have a namespace (nor Broker, user/repo, etc.) at that point. -Which namespace the EventType should be created on? Pointing to which Broker? -Implementation-wise, one potential solution is to have a controller for source CRDs, whenever one is installed, search for all the namespaces with -eventing enabled (`kubectl get namespaces -l knative-eventing-injection=enabled`), and adding all the possible EventTypes from that CRD to each of -the Brokers in those namespaces. A downside of this is that the Registry information is not "accurate", in the sense that it only has info about EventTypes -that may potentially flow in the system. But actually, they will only be able to flow when a CR is created. - -- ... - diff --git a/docs/registry/example_broker_policies.yaml b/docs/registry/example_broker_policies.yaml index 999ea6f6ce8..fedaeeb42b8 100644 --- a/docs/registry/example_broker_policies.yaml +++ b/docs/registry/example_broker_policies.yaml @@ -34,16 +34,3 @@ metadata: spec: ingressPolicy: allowAny: false - ---- - -# By setting the IngressPolicy to autoAdd, the broker will accept any event and will add them to the Registry, if -# not present. - -apiVersion: eventing.knative.dev/v1alpha1 -kind: Broker -metadata: - name: broker-auto-add -spec: - ingressPolicy: - autoAdd: true diff --git a/docs/registry/example_eventtype.yaml b/docs/registry/example_eventtype.yaml index b3b10d8e52a..844fcf67f1b 100644 --- a/docs/registry/example_eventtype.yaml +++ b/docs/registry/example_eventtype.yaml @@ -14,22 +14,23 @@ --- -# This EventType creates an event type with type 'repo:push' and source -# 'my-user/my-repo', for the 'broker-allow-registered' Broker. +# This EventType creates an event type with type 'com.github.pull_request', source +# 'github.com', for the 'broker-allow-registered' Broker. apiVersion: eventing.knative.dev/v1alpha1 kind: EventType metadata: - name: repopush + name: com.github.pullrequest spec: - type: repo:push - source: my-user/my-repo + type: com.github.pull_request + source: github.com broker: broker-allow-registered + description: "BitBucket Repo Push" --- -# This Trigger matches all events of type 'repo:push' and source -# 'my-user/my-repo', that are sent to the 'broker-allow-registered' Broker. +# This Trigger matches all events of type 'com.github.pull_request' and source +# 'github.com', that are sent to the 'broker-allow-registered' Broker. apiVersion: eventing.knative.dev/v1alpha1 kind: Trigger @@ -38,8 +39,8 @@ metadata: spec: filter: sourceAndType: - type: repo:push - source: my-user/my-repo + type: com.github.pull_request + source: github.com broker: broker-allow-registered subscriber: ref: diff --git a/pkg/broker/context.go b/pkg/broker/context.go index 9d87fb023fc..fd336f5123e 100644 --- a/pkg/broker/context.go +++ b/pkg/broker/context.go @@ -22,17 +22,10 @@ import ( "net/url" "strings" - "github.com/cloudevents/sdk-go" + cloudevents "github.com/cloudevents/sdk-go" "k8s.io/apimachinery/pkg/util/sets" ) -const ( - // Custom extension to match the EventType, if present. - // Otherwise we use the CloudEvent source attribute. - // This should be hopefully populated by the sources that we have control over. - extensionFrom = "from" -) - var ( // These MUST be lowercase strings, as they will be compared against lowercase strings. forwardHeaders = sets.NewString( diff --git a/pkg/broker/ingress.go b/pkg/broker/ingress.go index 973de60fa96..4c8a2bdb655 100644 --- a/pkg/broker/ingress.go +++ b/pkg/broker/ingress.go @@ -18,9 +18,7 @@ package broker import ( "context" - "fmt" - - "github.com/knative/eventing/pkg/utils" + "strings" "go.uber.org/zap" @@ -88,12 +86,11 @@ func (p *IngressPolicy) isRegistered(ctx context.Context, event cloudevents.Even // getEventType retrieves the EventType from the Registry for the given cloudevents.Event. // If it is not found, it returns an error. func (p *IngressPolicy) getEventType(ctx context.Context, event cloudevents.Event) (*eventingv1alpha1.EventType, error) { - source := fromOrSource(event) - opts := &client.ListOptions{ Namespace: p.namespace, // Set Raw because if we need to get more than one page, then we will put the continue token // into opts.Raw.Continue. + // TODO filter by Broker label. Raw: &metav1.ListOptions{}, } @@ -105,9 +102,10 @@ func (p *IngressPolicy) getEventType(ctx context.Context, event cloudevents.Even } for _, et := range etl.Items { if et.Spec.Broker == p.broker { - // Matching on type, schemaURL, and "source" (either our custom extension 'from' or the CloudEvent source). - // Note that if we end up using the CloudEvent source, most probably the EventType won't be there. - if et.Spec.Type == event.Type() && et.Spec.Source == source && et.Spec.Schema == event.SchemaURL() { + // Matching on type, source, and schemaURL. + // Note that if we the CloudEvent comes with a very specific source (i.e., without the split of + // source and subject proposed in v0.3), the EventType most probably won't be there. + if strings.EqualFold(et.Spec.Type, event.Type()) && strings.EqualFold(et.Spec.Source, event.Source()) && strings.EqualFold(et.Spec.Schema, event.SchemaURL()) { return &et, nil } } @@ -119,35 +117,3 @@ func (p *IngressPolicy) getEventType(ctx context.Context, event cloudevents.Even } } } - -// makeEventType generates, but does not create an EventType from the given cloudevents.Event. -func (p *IngressPolicy) makeEventType(event cloudevents.Event) *eventingv1alpha1.EventType { - source := fromOrSource(event) - cloudEventType := event.Type() - return &eventingv1alpha1.EventType{ - ObjectMeta: metav1.ObjectMeta{ - GenerateName: fmt.Sprintf("%s-", utils.ToDNS1123Subdomain(cloudEventType)), - Namespace: p.namespace, - }, - Spec: eventingv1alpha1.EventTypeSpec{ - Type: cloudEventType, - Source: source, - Schema: event.SchemaURL(), - Broker: p.broker, - }, - } -} - -// Retrieve the custom extension 'From' as opposed to CloudEvent source, if available. -// If the extension is populated, it means the event came from one of our sources. -// Note that some of our sources might not populate this, e.g., container source, etc., so we just retrieve the CloudEvent -// source. -func fromOrSource(event cloudevents.Event) string { - source := event.Source() - var from string - err := event.ExtensionAs(extensionFrom, &from) - if err == nil { - source = from - } - return source -} diff --git a/pkg/broker/ingress_test.go b/pkg/broker/ingress_test.go index 6357e2aa67e..9dabb5585fc 100644 --- a/pkg/broker/ingress_test.go +++ b/pkg/broker/ingress_test.go @@ -23,8 +23,6 @@ import ( "net/url" "testing" - "k8s.io/apimachinery/pkg/api/equality" - "sigs.k8s.io/controller-runtime/pkg/client" "go.uber.org/zap" @@ -45,7 +43,6 @@ const ( testType = "test-type" otherType = "other-test-type" testSource = "/test-source" - testFrom = "/test-from" ) func init() { @@ -55,10 +52,6 @@ func init() { func TestIngress(t *testing.T) { - extensions := map[string]interface{}{ - extensionFrom: testFrom, - } - testCases := map[string]struct { eventTypes []*eventingv1alpha1.EventType mocks controllertesting.Mocks @@ -98,16 +91,6 @@ func TestIngress(t *testing.T) { }, want: false, }, - "allow registered, event not found with from, reject": { - policySpec: &eventingv1alpha1.IngressPolicySpec{ - AllowAny: false, - }, - event: makeCloudEvent(extensions), - eventTypes: []*eventingv1alpha1.EventType{ - makeEventType(testType, testSource), - }, - want: false, - }, "allow registered, event registered, accept": { policySpec: &eventingv1alpha1.IngressPolicySpec{ AllowAny: false, @@ -118,63 +101,6 @@ func TestIngress(t *testing.T) { }, want: true, }, - "allow registered, event registered with from, accept": { - policySpec: &eventingv1alpha1.IngressPolicySpec{ - AllowAny: false, - }, - event: makeCloudEvent(extensions), - eventTypes: []*eventingv1alpha1.EventType{ - makeEventType(testType, testFrom), - }, - want: true, - }, - "auto add, error listing types, accept": { - policySpec: &eventingv1alpha1.IngressPolicySpec{ - AutoAdd: true, - }, - event: makeCloudEvent(nil), - mocks: controllertesting.Mocks{ - MockLists: []controllertesting.MockList{ - func(_ client.Client, _ context.Context, _ *client.ListOptions, _ runtime.Object) (controllertesting.MockHandled, error) { - return controllertesting.Handled, errors.New("error listing types") - }, - }, - }, - want: true, - }, - "auto add, error creating type, accept": { - policySpec: &eventingv1alpha1.IngressPolicySpec{ - AutoAdd: true, - }, - event: makeCloudEvent(nil), - mocks: controllertesting.Mocks{ - MockCreates: []controllertesting.MockCreate{ - func(_ client.Client, _ context.Context, obj runtime.Object) (controllertesting.MockHandled, error) { - return controllertesting.Handled, errors.New("error creating type") - }, - }, - }, - want: true, - }, - "auto add, created type, accept": { - policySpec: &eventingv1alpha1.IngressPolicySpec{ - AutoAdd: true, - }, - event: makeCloudEvent(nil), - mocks: controllertesting.Mocks{ - MockCreates: []controllertesting.MockCreate{ - func(_ client.Client, _ context.Context, obj runtime.Object) (controllertesting.MockHandled, error) { - et := obj.(*eventingv1alpha1.EventType) - expected := makeEventType(testType, testSource).Spec - if !equality.Semantic.DeepDerivative(et.Spec, expected) { - return controllertesting.Handled, errors.New("error creating type") - } - return controllertesting.Unhandled, nil - }, - }, - }, - want: true, - }, } for n, tc := range testCases { t.Run(n, func(t *testing.T) { diff --git a/pkg/broker/receiver.go b/pkg/broker/receiver.go index dc0083ea7de..86b5c4381ef 100644 --- a/pkg/broker/receiver.go +++ b/pkg/broker/receiver.go @@ -23,7 +23,7 @@ import ( "net/url" "time" - "github.com/cloudevents/sdk-go" + cloudevents "github.com/cloudevents/sdk-go" eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" "github.com/knative/eventing/pkg/reconciler/trigger/path" "go.uber.org/zap" @@ -215,17 +215,6 @@ func (r *Receiver) shouldSendMessage(ts *eventingv1alpha1.TriggerSpec, event *cl } filterSource := ts.Filter.SourceAndType.Source actualSource := event.Source() - // We look if there is a From extension, which means that it is a known type that came from our sources. - // If it is there, then we update the actualSource variable and compare against this one. - // This is a hack not to change how we define trigger filters, and to make the source field usable, without needing - // more advanced filtering. - // TODO should be updated once we decide on filtering languages. - var from string - err := event.ExtensionAs(extensionFrom, &from) - if err == nil { - actualSource = from - } - if filterSource != eventingv1alpha1.TriggerAnyFilter && filterSource != actualSource { r.logger.Debug("Wrong source", zap.String("trigger.spec.filter.sourceAndType.source", filterSource), zap.String("message.source", actualSource)) return false From b69f64339f662e53f2453f81d1be1eeae7818ce5 Mon Sep 17 00:00:00 2001 From: nachocano Date: Thu, 25 Apr 2019 13:00:39 -0700 Subject: [PATCH 210/221] some updates, still broken --- Gopkg.lock | 10 + .../aws/aws-sdk-go/aws/endpoints/defaults.go | 65 +-- .../github.com/aws/aws-sdk-go/aws/version.go | 2 +- .../gen-go/agent/common/v1/common.pb.go | 6 +- .../gen-go/metrics/v1/metrics.pb.go | 420 ++++++++++++++---- .../gen-go/resource/v1/resource.pb.go | 2 +- vendor/github.com/spf13/pflag/bytes.go | 104 +++++ vendor/github.com/spf13/pflag/flag.go | 10 +- .../github.com/spf13/pflag/string_to_int.go | 149 +++++++ .../spf13/pflag/string_to_string.go | 160 +++++++ 10 files changed, 770 insertions(+), 158 deletions(-) create mode 100644 vendor/github.com/spf13/pflag/string_to_int.go create mode 100644 vendor/github.com/spf13/pflag/string_to_string.go diff --git a/Gopkg.lock b/Gopkg.lock index 0fd66fadcbc..66f06646221 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -424,6 +424,14 @@ pruneopts = "NUT" revision = "f2b4162afba35581b6d4a50d3b8f34e33c144682" +[[projects]] + digest = "1:b8870bf2606dca65dc382f4cb8b7a434f17ff36a915451bda12788e9620be368" + name = "github.com/kelseyhightower/envconfig" + packages = ["."] + pruneopts = "NUT" + revision = "f611eb38b3875cc3bd991ca91c51d06446afa14c" + version = "v1.3.0" + [[projects]] digest = "1:57d04562d05dd4500ff1e7e47f2e62b9be0531388377a3b691a012ce70b210d5" name = "github.com/knative/pkg" @@ -1375,6 +1383,7 @@ "github.com/google/go-cmp/cmp", "github.com/google/go-cmp/cmp/cmpopts", "github.com/google/uuid", + "github.com/kelseyhightower/envconfig", "github.com/knative/pkg/apis", "github.com/knative/pkg/apis/duck", "github.com/knative/pkg/apis/duck/v1alpha1", @@ -1432,6 +1441,7 @@ "k8s.io/apimachinery/pkg/util/sets", "k8s.io/apimachinery/pkg/util/sets/types", "k8s.io/apimachinery/pkg/util/uuid", + "k8s.io/apimachinery/pkg/util/validation", "k8s.io/apimachinery/pkg/util/wait", "k8s.io/apimachinery/pkg/util/yaml", "k8s.io/apimachinery/pkg/watch", diff --git a/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go b/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go index b09e0cc4ab7..d020c66c28c 100644 --- a/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go +++ b/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go @@ -174,19 +174,14 @@ var awsPartition = partition{ }, Endpoints: endpoints{ "ap-northeast-1": endpoint{}, - "ap-northeast-2": endpoint{}, - "ap-south-1": endpoint{}, "ap-southeast-1": endpoint{}, "ap-southeast-2": endpoint{}, "ca-central-1": endpoint{}, "eu-central-1": endpoint{}, - "eu-north-1": endpoint{}, "eu-west-1": endpoint{}, "eu-west-2": endpoint{}, - "eu-west-3": endpoint{}, "us-east-1": endpoint{}, "us-east-2": endpoint{}, - "us-west-1": endpoint{}, "us-west-2": endpoint{}, }, }, @@ -568,7 +563,6 @@ var awsPartition = partition{ "cloud9": service{ Endpoints: endpoints{ - "ap-northeast-1": endpoint{}, "ap-southeast-1": endpoint{}, "eu-west-1": endpoint{}, "us-east-1": endpoint{}, @@ -1319,10 +1313,9 @@ var awsPartition = partition{ "email": service{ Endpoints: endpoints{ - "eu-central-1": endpoint{}, - "eu-west-1": endpoint{}, - "us-east-1": endpoint{}, - "us-west-2": endpoint{}, + "eu-west-1": endpoint{}, + "us-east-1": endpoint{}, + "us-west-2": endpoint{}, }, }, "entitlement.marketplace": service{ @@ -1421,7 +1414,6 @@ var awsPartition = partition{ Endpoints: endpoints{ "ap-northeast-1": endpoint{}, - "ap-southeast-2": endpoint{}, "eu-west-1": endpoint{}, "us-east-1": endpoint{}, "us-east-2": endpoint{}, @@ -2486,7 +2478,6 @@ var awsPartition = partition{ "ap-southeast-2": endpoint{}, "ca-central-1": endpoint{}, "eu-central-1": endpoint{}, - "eu-north-1": endpoint{}, "eu-west-1": endpoint{}, "eu-west-2": endpoint{}, "eu-west-3": endpoint{}, @@ -2567,9 +2558,6 @@ var awsPartition = partition{ "eu-central-1": endpoint{ Protocols: []string{"https"}, }, - "eu-north-1": endpoint{ - Protocols: []string{"https"}, - }, "eu-west-1": endpoint{ Protocols: []string{"https"}, }, @@ -2681,7 +2669,6 @@ var awsPartition = partition{ "ap-southeast-2": endpoint{}, "ca-central-1": endpoint{}, "eu-central-1": endpoint{}, - "eu-north-1": endpoint{}, "eu-west-1": endpoint{}, "eu-west-2": endpoint{}, "eu-west-3": endpoint{}, @@ -3206,20 +3193,6 @@ var awscnPartition = partition{ "cn-northwest-1": endpoint{}, }, }, - "cloudfront": service{ - PartitionEndpoint: "aws-cn-global", - IsRegionalized: boxedFalse, - - Endpoints: endpoints{ - "aws-cn-global": endpoint{ - Hostname: "cloudfront.cn-northwest-1.amazonaws.com.cn", - Protocols: []string{"http", "https"}, - CredentialScope: credentialScope{ - Region: "cn-northwest-1", - }, - }, - }, - }, "cloudtrail": service{ Endpoints: endpoints{ @@ -3423,12 +3396,6 @@ var awscnPartition = partition{ "cn-northwest-1": endpoint{}, }, }, - "mediaconvert": service{ - - Endpoints: endpoints{ - "cn-northwest-1": endpoint{}, - }, - }, "monitoring": service{ Defaults: endpoint{ Protocols: []string{"http", "https"}, @@ -3708,12 +3675,6 @@ var awsusgovPartition = partition{ "us-gov-west-1": endpoint{}, }, }, - "codecommit": service{ - - Endpoints: endpoints{ - "us-gov-west-1": endpoint{}, - }, - }, "codedeploy": service{ Endpoints: endpoints{ @@ -3957,13 +3918,6 @@ var awsusgovPartition = partition{ "us-gov-west-1": endpoint{}, }, }, - "license-manager": service{ - - Endpoints: endpoints{ - "us-gov-east-1": endpoint{}, - "us-gov-west-1": endpoint{}, - }, - }, "logs": service{ Endpoints: endpoints{ @@ -3994,19 +3948,6 @@ var awsusgovPartition = partition{ "us-gov-west-1": endpoint{}, }, }, - "organizations": service{ - PartitionEndpoint: "aws-us-gov-global", - IsRegionalized: boxedFalse, - - Endpoints: endpoints{ - "aws-us-gov-global": endpoint{ - Hostname: "organizations.us-gov-west-1.amazonaws.com", - CredentialScope: credentialScope{ - Region: "us-gov-west-1", - }, - }, - }, - }, "polly": service{ Endpoints: endpoints{ diff --git a/vendor/github.com/aws/aws-sdk-go/aws/version.go b/vendor/github.com/aws/aws-sdk-go/aws/version.go index d5cd4e9baa8..1d96f9c0b37 100644 --- a/vendor/github.com/aws/aws-sdk-go/aws/version.go +++ b/vendor/github.com/aws/aws-sdk-go/aws/version.go @@ -5,4 +5,4 @@ package aws const SDKName = "aws-sdk-go" // SDKVersion is the version of this SDK -const SDKVersion = "1.19.17" +const SDKVersion = "1.19.11" diff --git a/vendor/github.com/census-instrumentation/opencensus-proto/gen-go/agent/common/v1/common.pb.go b/vendor/github.com/census-instrumentation/opencensus-proto/gen-go/agent/common/v1/common.pb.go index 12b578d068d..2f12e428ede 100644 --- a/vendor/github.com/census-instrumentation/opencensus-proto/gen-go/agent/common/v1/common.pb.go +++ b/vendor/github.com/census-instrumentation/opencensus-proto/gen-go/agent/common/v1/common.pb.go @@ -19,7 +19,7 @@ var _ = math.Inf // is compatible with the proto package it is being compiled against. // A compilation error at this line likely means your copy of the // proto package needs to be updated. -const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package type LibraryInfo_Language int32 @@ -70,8 +70,8 @@ func (LibraryInfo_Language) EnumDescriptor() ([]byte, []int) { return fileDescriptor_126c72ed8a252c84, []int{2, 0} } -// Identifier metadata of the Node that produces the span or tracing data. -// Note, this is not the metadata about the Node or service that is described by associated spans. +// Identifier metadata of the Node (Application instrumented with OpenCensus) +// that connects to OpenCensus Agent. // In the future we plan to extend the identifier proto definition to support // additional information (e.g cloud id, etc.) type Node struct { diff --git a/vendor/github.com/census-instrumentation/opencensus-proto/gen-go/metrics/v1/metrics.pb.go b/vendor/github.com/census-instrumentation/opencensus-proto/gen-go/metrics/v1/metrics.pb.go index 53b8aa99e16..6759ced888b 100644 --- a/vendor/github.com/census-instrumentation/opencensus-proto/gen-go/metrics/v1/metrics.pb.go +++ b/vendor/github.com/census-instrumentation/opencensus-proto/gen-go/metrics/v1/metrics.pb.go @@ -21,7 +21,7 @@ var _ = math.Inf // is compatible with the proto package it is being compiled against. // A compilation error at this line likely means your copy of the // proto package needs to be updated. -const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package // The kind of metric. It describes how the data is reported. // @@ -96,16 +96,20 @@ func (MetricDescriptor_Type) EnumDescriptor() ([]byte, []int) { // Defines a Metric which has one or more timeseries. type Metric struct { - // The descriptor of the Metric. - // TODO(issue #152): consider only sending the name of descriptor for - // optimization. - MetricDescriptor *MetricDescriptor `protobuf:"bytes,1,opt,name=metric_descriptor,json=metricDescriptor,proto3" json:"metric_descriptor,omitempty"` + // The descriptor of the Metric. This is an optimization for network wire + // size, from data-model perspective a Metric contains always a + // MetricDescriptor. + // + // Types that are valid to be assigned to Descriptor_: + // *Metric_MetricDescriptor + // *Metric_Name + Descriptor_ isMetric_Descriptor_ `protobuf_oneof:"descriptor"` // One or more timeseries for a single metric, where each timeseries has // one or more points. - Timeseries []*TimeSeries `protobuf:"bytes,2,rep,name=timeseries,proto3" json:"timeseries,omitempty"` + Timeseries []*TimeSeries `protobuf:"bytes,3,rep,name=timeseries,proto3" json:"timeseries,omitempty"` // The resource for the metric. If unset, it may be set to a default value // provided for a sequence of messages in an RPC stream. - Resource *v1.Resource `protobuf:"bytes,3,opt,name=resource,proto3" json:"resource,omitempty"` + Resource *v1.Resource `protobuf:"bytes,4,opt,name=resource,proto3" json:"resource,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -136,13 +140,43 @@ func (m *Metric) XXX_DiscardUnknown() { var xxx_messageInfo_Metric proto.InternalMessageInfo -func (m *Metric) GetMetricDescriptor() *MetricDescriptor { +type isMetric_Descriptor_ interface { + isMetric_Descriptor_() +} + +type Metric_MetricDescriptor struct { + MetricDescriptor *MetricDescriptor `protobuf:"bytes,1,opt,name=metric_descriptor,json=metricDescriptor,proto3,oneof"` +} + +type Metric_Name struct { + Name string `protobuf:"bytes,2,opt,name=name,proto3,oneof"` +} + +func (*Metric_MetricDescriptor) isMetric_Descriptor_() {} + +func (*Metric_Name) isMetric_Descriptor_() {} + +func (m *Metric) GetDescriptor_() isMetric_Descriptor_ { if m != nil { - return m.MetricDescriptor + return m.Descriptor_ + } + return nil +} + +func (m *Metric) GetMetricDescriptor() *MetricDescriptor { + if x, ok := m.GetDescriptor_().(*Metric_MetricDescriptor); ok { + return x.MetricDescriptor } return nil } +func (m *Metric) GetName() string { + if x, ok := m.GetDescriptor_().(*Metric_Name); ok { + return x.Name + } + return "" +} + func (m *Metric) GetTimeseries() []*TimeSeries { if m != nil { return m.Timeseries @@ -157,6 +191,76 @@ func (m *Metric) GetResource() *v1.Resource { return nil } +// XXX_OneofFuncs is for the internal use of the proto package. +func (*Metric) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) { + return _Metric_OneofMarshaler, _Metric_OneofUnmarshaler, _Metric_OneofSizer, []interface{}{ + (*Metric_MetricDescriptor)(nil), + (*Metric_Name)(nil), + } +} + +func _Metric_OneofMarshaler(msg proto.Message, b *proto.Buffer) error { + m := msg.(*Metric) + // descriptor + switch x := m.Descriptor_.(type) { + case *Metric_MetricDescriptor: + b.EncodeVarint(1<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.MetricDescriptor); err != nil { + return err + } + case *Metric_Name: + b.EncodeVarint(2<<3 | proto.WireBytes) + b.EncodeStringBytes(x.Name) + case nil: + default: + return fmt.Errorf("Metric.Descriptor_ has unexpected type %T", x) + } + return nil +} + +func _Metric_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) { + m := msg.(*Metric) + switch tag { + case 1: // descriptor.metric_descriptor + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(MetricDescriptor) + err := b.DecodeMessage(msg) + m.Descriptor_ = &Metric_MetricDescriptor{msg} + return true, err + case 2: // descriptor.name + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeStringBytes() + m.Descriptor_ = &Metric_Name{x} + return true, err + default: + return false, nil + } +} + +func _Metric_OneofSizer(msg proto.Message) (n int) { + m := msg.(*Metric) + // descriptor + switch x := m.Descriptor_.(type) { + case *Metric_MetricDescriptor: + s := proto.Size(x.MetricDescriptor) + n += 1 // tag and wire + n += proto.SizeVarint(uint64(s)) + n += s + case *Metric_Name: + n += 1 // tag and wire + n += proto.SizeVarint(uint64(len(x.Name))) + n += len(x.Name) + case nil: + default: + panic(fmt.Sprintf("proto: unexpected type %T in oneof", x)) + } + return n +} + // Defines a metric type and its schema. type MetricDescriptor struct { // The metric type, including its DNS name prefix. It must be unique. @@ -513,9 +617,9 @@ func (m *Point) GetSummaryValue() *SummaryValue { return nil } -// XXX_OneofWrappers is for the internal use of the proto package. -func (*Point) XXX_OneofWrappers() []interface{} { - return []interface{}{ +// XXX_OneofFuncs is for the internal use of the proto package. +func (*Point) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) { + return _Point_OneofMarshaler, _Point_OneofUnmarshaler, _Point_OneofSizer, []interface{}{ (*Point_Int64Value)(nil), (*Point_DoubleValue)(nil), (*Point_DistributionValue)(nil), @@ -523,6 +627,98 @@ func (*Point) XXX_OneofWrappers() []interface{} { } } +func _Point_OneofMarshaler(msg proto.Message, b *proto.Buffer) error { + m := msg.(*Point) + // value + switch x := m.Value.(type) { + case *Point_Int64Value: + b.EncodeVarint(2<<3 | proto.WireVarint) + b.EncodeVarint(uint64(x.Int64Value)) + case *Point_DoubleValue: + b.EncodeVarint(3<<3 | proto.WireFixed64) + b.EncodeFixed64(math.Float64bits(x.DoubleValue)) + case *Point_DistributionValue: + b.EncodeVarint(4<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.DistributionValue); err != nil { + return err + } + case *Point_SummaryValue: + b.EncodeVarint(5<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.SummaryValue); err != nil { + return err + } + case nil: + default: + return fmt.Errorf("Point.Value has unexpected type %T", x) + } + return nil +} + +func _Point_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) { + m := msg.(*Point) + switch tag { + case 2: // value.int64_value + if wire != proto.WireVarint { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeVarint() + m.Value = &Point_Int64Value{int64(x)} + return true, err + case 3: // value.double_value + if wire != proto.WireFixed64 { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeFixed64() + m.Value = &Point_DoubleValue{math.Float64frombits(x)} + return true, err + case 4: // value.distribution_value + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(DistributionValue) + err := b.DecodeMessage(msg) + m.Value = &Point_DistributionValue{msg} + return true, err + case 5: // value.summary_value + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(SummaryValue) + err := b.DecodeMessage(msg) + m.Value = &Point_SummaryValue{msg} + return true, err + default: + return false, nil + } +} + +func _Point_OneofSizer(msg proto.Message) (n int) { + m := msg.(*Point) + // value + switch x := m.Value.(type) { + case *Point_Int64Value: + n += 1 // tag and wire + n += proto.SizeVarint(uint64(x.Int64Value)) + case *Point_DoubleValue: + n += 1 // tag and wire + n += 8 + case *Point_DistributionValue: + s := proto.Size(x.DistributionValue) + n += 1 // tag and wire + n += proto.SizeVarint(uint64(s)) + n += s + case *Point_SummaryValue: + s := proto.Size(x.SummaryValue) + n += 1 // tag and wire + n += proto.SizeVarint(uint64(s)) + n += s + case nil: + default: + panic(fmt.Sprintf("proto: unexpected type %T in oneof", x)) + } + return n +} + // Distribution contains summary statistics for a population of values. It // optionally contains a histogram representing the distribution of those // values across a set of buckets. @@ -545,9 +741,8 @@ type DistributionValue struct { // If count is zero then this field must be zero. SumOfSquaredDeviation float64 `protobuf:"fixed64,3,opt,name=sum_of_squared_deviation,json=sumOfSquaredDeviation,proto3" json:"sum_of_squared_deviation,omitempty"` // Don't change bucket boundaries within a TimeSeries if your backend doesn't - // support this. - // TODO(issue #152): consider not required to send bucket options for - // optimization. + // support this. To save network bandwidth this field can be sent only the + // first time a metric is sent when using a streaming RPC. BucketOptions *DistributionValue_BucketOptions `protobuf:"bytes,4,opt,name=bucket_options,json=bucketOptions,proto3" json:"bucket_options,omitempty"` // If the distribution does not have a histogram, then omit this field. // If there is a histogram, then the sum of the values in the Bucket counts @@ -682,20 +877,68 @@ func (m *DistributionValue_BucketOptions) GetExplicit() *DistributionValue_Bucke return nil } -// XXX_OneofWrappers is for the internal use of the proto package. -func (*DistributionValue_BucketOptions) XXX_OneofWrappers() []interface{} { - return []interface{}{ +// XXX_OneofFuncs is for the internal use of the proto package. +func (*DistributionValue_BucketOptions) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) { + return _DistributionValue_BucketOptions_OneofMarshaler, _DistributionValue_BucketOptions_OneofUnmarshaler, _DistributionValue_BucketOptions_OneofSizer, []interface{}{ (*DistributionValue_BucketOptions_Explicit_)(nil), } } +func _DistributionValue_BucketOptions_OneofMarshaler(msg proto.Message, b *proto.Buffer) error { + m := msg.(*DistributionValue_BucketOptions) + // type + switch x := m.Type.(type) { + case *DistributionValue_BucketOptions_Explicit_: + b.EncodeVarint(1<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.Explicit); err != nil { + return err + } + case nil: + default: + return fmt.Errorf("DistributionValue_BucketOptions.Type has unexpected type %T", x) + } + return nil +} + +func _DistributionValue_BucketOptions_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) { + m := msg.(*DistributionValue_BucketOptions) + switch tag { + case 1: // type.explicit + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(DistributionValue_BucketOptions_Explicit) + err := b.DecodeMessage(msg) + m.Type = &DistributionValue_BucketOptions_Explicit_{msg} + return true, err + default: + return false, nil + } +} + +func _DistributionValue_BucketOptions_OneofSizer(msg proto.Message) (n int) { + m := msg.(*DistributionValue_BucketOptions) + // type + switch x := m.Type.(type) { + case *DistributionValue_BucketOptions_Explicit_: + s := proto.Size(x.Explicit) + n += 1 // tag and wire + n += proto.SizeVarint(uint64(s)) + n += s + case nil: + default: + panic(fmt.Sprintf("proto: unexpected type %T in oneof", x)) + } + return n +} + // Specifies a set of buckets with arbitrary upper-bounds. // This defines size(bounds) + 1 (= N) buckets. The boundaries for bucket // index i are: // // [0, bucket_bounds[i]) for i == 0 // [bucket_bounds[i-1], bucket_bounds[i]) for 0 < i < N-1 -// [bucket_bounds[i], +infinity) for i == N-1 +// [bucket_bounds[i-1], +infinity) for i == N-1 type DistributionValue_BucketOptions_Explicit struct { // The values must be strictly increasing and > 0. Bounds []float64 `protobuf:"fixed64,1,rep,packed,name=bounds,proto3" json:"bounds,omitempty"` @@ -1053,74 +1296,75 @@ func init() { } var fileDescriptor_0ee3deb72053811a = []byte{ - // 1098 bytes of a gzipped FileDescriptorProto + // 1114 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x56, 0xdd, 0x6e, 0x1b, 0xc5, - 0x17, 0xcf, 0xda, 0x8e, 0xe3, 0x9c, 0x75, 0xdb, 0xf5, 0xa8, 0xed, 0xdf, 0xda, 0xfc, 0x15, 0xc2, - 0x22, 0x20, 0x15, 0xca, 0x5a, 0x31, 0xa5, 0xad, 0x2a, 0x54, 0x14, 0xc7, 0x6e, 0x62, 0xc8, 0x87, - 0x35, 0xb6, 0x2b, 0xd1, 0x1b, 0x6b, 0xbd, 0x9e, 0x24, 0x4b, 0xbc, 0x1f, 0xdd, 0x99, 0x35, 0xf8, - 0x05, 0x78, 0x04, 0xae, 0xb9, 0x45, 0x3c, 0x07, 0x57, 0x3c, 0x01, 0x4f, 0x81, 0x78, 0x03, 0xb4, - 0x33, 0xb3, 0x1f, 0x89, 0xc1, 0xd4, 0x45, 0xe2, 0xee, 0x9c, 0x33, 0xe7, 0xfc, 0xfc, 0x3b, 0x9f, - 0x5e, 0x78, 0xe4, 0x07, 0xc4, 0xb3, 0x89, 0x47, 0x23, 0xda, 0x08, 0x42, 0x9f, 0xf9, 0x0d, 0x97, - 0xb0, 0xd0, 0xb1, 0x69, 0x63, 0xb6, 0x9f, 0x88, 0x26, 0x7f, 0x40, 0x5b, 0x99, 0xab, 0xb0, 0x98, - 0xc9, 0xfb, 0x6c, 0x5f, 0x7f, 0xef, 0xd2, 0xf7, 0x2f, 0xa7, 0x44, 0x60, 0x8c, 0xa3, 0x8b, 0x06, - 0x73, 0x5c, 0x42, 0x99, 0xe5, 0x06, 0xc2, 0x57, 0xdf, 0xbe, 0xed, 0xf0, 0x6d, 0x68, 0x05, 0x01, - 0x09, 0x25, 0x96, 0xfe, 0xc9, 0x02, 0x91, 0x90, 0x50, 0x3f, 0x0a, 0x6d, 0x12, 0x33, 0x49, 0x64, - 0xe1, 0x6c, 0xfc, 0xa1, 0x40, 0xf9, 0x94, 0xff, 0x38, 0x7a, 0x0d, 0x35, 0x41, 0x63, 0x34, 0x21, - 0xd4, 0x0e, 0x9d, 0x80, 0xf9, 0x61, 0x5d, 0xd9, 0x51, 0x76, 0xd5, 0xe6, 0x9e, 0xb9, 0x84, 0xb1, - 0x29, 0xe2, 0xdb, 0x69, 0x10, 0xd6, 0xdc, 0x5b, 0x16, 0x74, 0x04, 0xc0, 0xd3, 0x20, 0xa1, 0x43, - 0x68, 0xbd, 0xb0, 0x53, 0xdc, 0x55, 0x9b, 0x1f, 0x2f, 0x05, 0x1d, 0x38, 0x2e, 0xe9, 0x73, 0x77, - 0x9c, 0x0b, 0x45, 0x2d, 0xa8, 0x24, 0x19, 0xd4, 0x8b, 0x9c, 0xdb, 0x47, 0x8b, 0x30, 0x69, 0x8e, - 0xb3, 0x7d, 0x13, 0x4b, 0x19, 0xa7, 0x71, 0xc6, 0x0f, 0x45, 0xd0, 0x6e, 0x73, 0x46, 0x08, 0x4a, - 0x9e, 0xe5, 0x12, 0x9e, 0xf0, 0x26, 0xe6, 0x32, 0xda, 0x01, 0x35, 0x29, 0x85, 0xe3, 0x7b, 0xf5, - 0x02, 0x7f, 0xca, 0x9b, 0xe2, 0xa8, 0xc8, 0x73, 0x18, 0xa7, 0xb2, 0x89, 0xb9, 0x8c, 0x5e, 0x42, - 0x89, 0xcd, 0x03, 0x52, 0x2f, 0xed, 0x28, 0xbb, 0x77, 0x9b, 0xcd, 0x95, 0x4a, 0x67, 0x0e, 0xe6, - 0x01, 0xc1, 0x3c, 0x1e, 0xb5, 0x01, 0xa6, 0xd6, 0x98, 0x4c, 0x47, 0xd7, 0x64, 0x4e, 0xeb, 0xeb, - 0xbc, 0x66, 0x1f, 0x2e, 0x45, 0x3b, 0x89, 0xdd, 0xbf, 0x22, 0x73, 0xbc, 0x39, 0x95, 0x12, 0x35, - 0x7e, 0x52, 0xa0, 0x14, 0x83, 0xa2, 0x7b, 0xa0, 0x0e, 0xcf, 0xfa, 0xbd, 0xce, 0x61, 0xf7, 0x65, - 0xb7, 0xd3, 0xd6, 0xd6, 0x62, 0xc3, 0xd1, 0xc1, 0xf0, 0xa8, 0x33, 0xea, 0x9e, 0x0d, 0x9e, 0x3c, - 0xd6, 0x14, 0xa4, 0x41, 0x55, 0x18, 0xda, 0xe7, 0xc3, 0xd6, 0x49, 0x47, 0x2b, 0xa0, 0x87, 0x80, - 0xa4, 0xa5, 0xdb, 0x1f, 0xe0, 0x6e, 0x6b, 0x38, 0xe8, 0x9e, 0x9f, 0x69, 0x45, 0x74, 0x1f, 0xb4, - 0xc3, 0xe1, 0xe9, 0xf0, 0xe4, 0x60, 0xd0, 0x7d, 0x95, 0xc4, 0x97, 0xd0, 0x03, 0xa8, 0xe5, 0xac, - 0x12, 0x64, 0x1d, 0x6d, 0xc1, 0xff, 0xf2, 0xe6, 0x3c, 0x52, 0x19, 0xa9, 0xb0, 0xd1, 0x1f, 0x9e, - 0x9e, 0x1e, 0xe0, 0xaf, 0xb5, 0x0d, 0xe3, 0x05, 0x54, 0x92, 0x14, 0x90, 0x06, 0xc5, 0x6b, 0x32, - 0x97, 0xed, 0x88, 0xc5, 0x7f, 0xee, 0x86, 0xf1, 0x9b, 0x02, 0x90, 0xcd, 0x0d, 0x3a, 0x84, 0x7b, - 0x94, 0x59, 0x21, 0x1b, 0xa5, 0x1b, 0x24, 0xc7, 0x59, 0x37, 0xc5, 0x0a, 0x99, 0xc9, 0x0a, 0xf1, - 0x69, 0xe3, 0x1e, 0xf8, 0x2e, 0x0f, 0x49, 0x75, 0xf4, 0x25, 0x54, 0x45, 0x17, 0x66, 0xd6, 0x34, - 0x7a, 0xcb, 0xd9, 0xe5, 0x49, 0xbc, 0x8a, 0xfd, 0xb1, 0x3a, 0x4d, 0x65, 0x8a, 0x9e, 0x43, 0x39, - 0xf0, 0x1d, 0x8f, 0xd1, 0x7a, 0x91, 0xa3, 0x18, 0x4b, 0x51, 0x7a, 0xb1, 0x2b, 0x96, 0x11, 0xc6, - 0x17, 0x00, 0x19, 0x2c, 0xba, 0x0f, 0xeb, 0x9c, 0x8f, 0xac, 0x8f, 0x50, 0xd0, 0x16, 0x6c, 0x5e, - 0x59, 0x54, 0x30, 0xe5, 0xf5, 0xa9, 0xe0, 0xca, 0x95, 0x45, 0x79, 0x88, 0xf1, 0x4b, 0x01, 0xd6, - 0x39, 0x24, 0x7a, 0x06, 0x9b, 0xab, 0x54, 0x24, 0x73, 0x46, 0xef, 0x83, 0xea, 0x78, 0xec, 0xc9, - 0xe3, 0xdc, 0x4f, 0x14, 0x8f, 0xd7, 0x30, 0x70, 0xa3, 0x60, 0xf6, 0x01, 0x54, 0x27, 0x7e, 0x34, - 0x9e, 0x12, 0xe9, 0x13, 0x6f, 0x86, 0x72, 0xbc, 0x86, 0x55, 0x61, 0x15, 0x4e, 0x23, 0x40, 0x13, - 0x87, 0xb2, 0xd0, 0x19, 0x47, 0x71, 0xe3, 0xa4, 0x6b, 0x89, 0x53, 0x31, 0x97, 0x16, 0xa5, 0x9d, - 0x0b, 0xe3, 0x58, 0xc7, 0x6b, 0xb8, 0x36, 0xb9, 0x6d, 0x44, 0x3d, 0xb8, 0x43, 0x23, 0xd7, 0xb5, - 0xc2, 0xb9, 0xc4, 0x5e, 0xe7, 0xd8, 0x8f, 0x96, 0x62, 0xf7, 0x45, 0x44, 0x02, 0x5b, 0xa5, 0x39, - 0xbd, 0xb5, 0x21, 0x2b, 0x6e, 0xfc, 0x5a, 0x86, 0xda, 0x02, 0x8b, 0xb8, 0x21, 0xb6, 0x1f, 0x79, - 0x8c, 0xd7, 0xb3, 0x88, 0x85, 0x12, 0x0f, 0x31, 0x8d, 0x5c, 0x5e, 0x27, 0x05, 0xc7, 0x22, 0x7a, - 0x0a, 0x75, 0x1a, 0xb9, 0x23, 0xff, 0x62, 0x44, 0xdf, 0x44, 0x56, 0x48, 0x26, 0xa3, 0x09, 0x99, - 0x39, 0x16, 0x9f, 0x68, 0x5e, 0x2a, 0xfc, 0x80, 0x46, 0xee, 0xf9, 0x45, 0x5f, 0xbc, 0xb6, 0x93, - 0x47, 0x64, 0xc3, 0xdd, 0x71, 0x64, 0x5f, 0x13, 0x36, 0xf2, 0xf9, 0xb0, 0x53, 0x59, 0xae, 0xcf, - 0x57, 0x2b, 0x97, 0xd9, 0xe2, 0x20, 0xe7, 0x02, 0x03, 0xdf, 0x19, 0xe7, 0x55, 0x74, 0x0e, 0x1b, - 0xc2, 0x90, 0xdc, 0x9b, 0xcf, 0xde, 0x09, 0x1d, 0x27, 0x28, 0xfa, 0x8f, 0x0a, 0xdc, 0xb9, 0xf1, - 0x8b, 0xc8, 0x86, 0x0a, 0xf9, 0x2e, 0x98, 0x3a, 0xb6, 0xc3, 0xe4, 0xec, 0x75, 0xfe, 0x4d, 0x06, - 0x66, 0x47, 0x82, 0x1d, 0xaf, 0xe1, 0x14, 0x58, 0x37, 0xa0, 0x92, 0xd8, 0xd1, 0x43, 0x28, 0x8f, - 0xfd, 0xc8, 0x9b, 0xd0, 0xba, 0xb2, 0x53, 0xdc, 0x55, 0xb0, 0xd4, 0x5a, 0x65, 0x71, 0xa6, 0x75, - 0x0a, 0x65, 0x81, 0xf8, 0x37, 0x3d, 0xec, 0xc7, 0x84, 0x89, 0x1b, 0x4c, 0xad, 0x90, 0x37, 0x52, - 0x6d, 0x3e, 0x5d, 0x91, 0x70, 0x47, 0x86, 0xe3, 0x14, 0x48, 0xff, 0xbe, 0x10, 0x33, 0x14, 0xca, - 0xcd, 0x65, 0x56, 0x92, 0x65, 0xbe, 0xb1, 0xa5, 0x85, 0x55, 0xb6, 0xf4, 0x1b, 0x50, 0x2d, 0xc6, - 0x2c, 0xfb, 0xca, 0x25, 0xd9, 0xad, 0x39, 0x7e, 0x47, 0xd2, 0xe6, 0x41, 0x06, 0xd5, 0xf1, 0x58, - 0x38, 0xc7, 0x79, 0x70, 0xfd, 0x05, 0x68, 0xb7, 0x1d, 0xfe, 0xe2, 0x74, 0xa7, 0x19, 0x16, 0x72, - 0xe7, 0xea, 0x79, 0xe1, 0x99, 0x62, 0xfc, 0x5e, 0x84, 0x6a, 0x7e, 0xef, 0xd0, 0x7e, 0xbe, 0x09, - 0x6a, 0x73, 0x6b, 0x21, 0xe5, 0x6e, 0x7a, 0x6b, 0x92, 0x0e, 0x99, 0xd9, 0x96, 0xa9, 0xcd, 0xff, - 0x2f, 0x04, 0xb4, 0xb3, 0xc3, 0x23, 0x76, 0xf0, 0x0c, 0x2a, 0xd4, 0xb3, 0x02, 0x7a, 0xe5, 0x33, - 0xf9, 0x0d, 0xd1, 0x7c, 0xeb, 0xbb, 0x60, 0xf6, 0x65, 0x24, 0x4e, 0x31, 0xf4, 0x9f, 0x0b, 0x50, - 0x49, 0xcc, 0xff, 0x05, 0xff, 0x37, 0x50, 0x0b, 0x48, 0x68, 0x13, 0x8f, 0x39, 0xc9, 0x99, 0x4d, - 0xba, 0xdc, 0x5e, 0x3d, 0x11, 0x93, 0xab, 0x07, 0xac, 0x97, 0x42, 0x62, 0x2d, 0x83, 0x17, 0xff, - 0x5c, 0x7a, 0x17, 0x6a, 0x0b, 0x6e, 0x68, 0x1b, 0x20, 0x73, 0x94, 0xc3, 0x9b, 0xb3, 0xdc, 0xec, - 0x7a, 0x32, 0xd7, 0xad, 0x19, 0x6c, 0x3b, 0xfe, 0x32, 0x9a, 0xad, 0xaa, 0xf8, 0x2a, 0xa2, 0xbd, - 0xf8, 0xa1, 0xa7, 0xbc, 0x6e, 0x5f, 0x3a, 0xec, 0x2a, 0x1a, 0x9b, 0xb6, 0xef, 0x36, 0x44, 0xcc, - 0x9e, 0xe3, 0x51, 0x16, 0x46, 0xf1, 0xcc, 0xf1, 0xeb, 0xd8, 0xc8, 0xe0, 0xf6, 0xc4, 0x27, 0xef, - 0x25, 0xf1, 0xf6, 0x2e, 0xf3, 0x9f, 0xe0, 0xe3, 0x32, 0x7f, 0xf8, 0xf4, 0xcf, 0x00, 0x00, 0x00, - 0xff, 0xff, 0x8e, 0xfc, 0xd7, 0x46, 0xa8, 0x0b, 0x00, 0x00, + 0x17, 0xf7, 0xda, 0x89, 0xe3, 0x9c, 0x75, 0xd3, 0xf5, 0x28, 0xed, 0xdf, 0x72, 0xfe, 0x0a, 0x61, + 0x11, 0x90, 0x0a, 0x65, 0xad, 0x98, 0xd2, 0x56, 0x15, 0x2a, 0x8a, 0x63, 0x37, 0x36, 0xe4, 0xc3, + 0x1a, 0xdb, 0x95, 0x40, 0x48, 0xd6, 0x7a, 0x3d, 0x49, 0x96, 0x78, 0x3f, 0xba, 0x33, 0x6b, 0xf0, + 0x0b, 0xf0, 0x08, 0x70, 0xcb, 0x2d, 0xe2, 0x39, 0xb8, 0xe2, 0x09, 0x78, 0x0a, 0x5e, 0x01, 0xed, + 0xcc, 0xec, 0x47, 0x62, 0x70, 0x71, 0x91, 0xb8, 0x9b, 0x73, 0xe6, 0xfc, 0x7e, 0x73, 0xbe, 0x77, + 0xe1, 0x91, 0xe7, 0x13, 0xd7, 0x22, 0x2e, 0x0d, 0x69, 0xdd, 0x0f, 0x3c, 0xe6, 0xd5, 0x1d, 0xc2, + 0x02, 0xdb, 0xa2, 0xf5, 0xd9, 0x61, 0x7c, 0x34, 0xf8, 0x05, 0xda, 0x49, 0x4d, 0x85, 0xc6, 0x88, + 0xef, 0x67, 0x87, 0xb5, 0x77, 0xae, 0x3c, 0xef, 0x6a, 0x4a, 0x04, 0xc7, 0x38, 0xbc, 0xac, 0x33, + 0xdb, 0x21, 0x94, 0x99, 0x8e, 0x2f, 0x6c, 0x6b, 0xbb, 0x77, 0x0d, 0xbe, 0x0d, 0x4c, 0xdf, 0x27, + 0x81, 0xe4, 0xaa, 0x7d, 0xb4, 0xe0, 0x48, 0x40, 0xa8, 0x17, 0x06, 0x16, 0x89, 0x3c, 0x89, 0xcf, + 0xc2, 0x58, 0xff, 0x31, 0x0f, 0xc5, 0x33, 0xfe, 0x38, 0xfa, 0x1a, 0x2a, 0xc2, 0x8d, 0xd1, 0x84, + 0x50, 0x2b, 0xb0, 0x7d, 0xe6, 0x05, 0x55, 0x65, 0x4f, 0xd9, 0x57, 0x1b, 0x07, 0xc6, 0x12, 0x8f, + 0x0d, 0x81, 0x6f, 0x25, 0xa0, 0x4e, 0x0e, 0x6b, 0xce, 0x1d, 0x1d, 0xda, 0x86, 0x35, 0xd7, 0x74, + 0x48, 0x35, 0xbf, 0xa7, 0xec, 0x6f, 0x76, 0x72, 0x98, 0x4b, 0xe8, 0x04, 0x80, 0x87, 0x47, 0x02, + 0x9b, 0xd0, 0x6a, 0x61, 0xaf, 0xb0, 0xaf, 0x36, 0x3e, 0x5c, 0xfa, 0xd8, 0xc0, 0x76, 0x48, 0x9f, + 0x9b, 0xe3, 0x0c, 0x14, 0x35, 0xa1, 0x14, 0x47, 0x56, 0x5d, 0xe3, 0x3e, 0x7f, 0xb0, 0x48, 0x93, + 0xc4, 0x3e, 0x3b, 0x34, 0xb0, 0x3c, 0xe3, 0x04, 0xd7, 0x2c, 0x03, 0xa4, 0x91, 0xeb, 0x3f, 0x14, + 0x40, 0xbb, 0x1b, 0x19, 0x42, 0x32, 0x8a, 0x28, 0x2d, 0x9b, 0x32, 0x86, 0x3d, 0x50, 0x63, 0x98, + 0xed, 0xb9, 0x22, 0x40, 0x9c, 0x55, 0x45, 0xa8, 0xd0, 0xb5, 0x59, 0xb5, 0x20, 0x50, 0xd1, 0x19, + 0xbd, 0x84, 0x35, 0x36, 0xf7, 0x85, 0xb3, 0x5b, 0x8d, 0xc6, 0x4a, 0x09, 0x36, 0x06, 0x73, 0x9f, + 0x60, 0x8e, 0x47, 0x2d, 0x80, 0xa9, 0x39, 0x26, 0xd3, 0xd1, 0x0d, 0x99, 0xd3, 0xea, 0x3a, 0xcf, + 0xe0, 0xfb, 0x4b, 0xd9, 0x4e, 0x23, 0xf3, 0x2f, 0xc8, 0x1c, 0x6f, 0x4e, 0xe5, 0x89, 0xea, 0x3f, + 0x2b, 0xb0, 0x16, 0x91, 0xa2, 0xfb, 0xa0, 0x0e, 0xcf, 0xfb, 0xbd, 0xf6, 0x71, 0xf7, 0x65, 0xb7, + 0xdd, 0xd2, 0x72, 0x91, 0xe2, 0xe4, 0x68, 0x78, 0xd2, 0x1e, 0x75, 0xcf, 0x07, 0x4f, 0x1e, 0x6b, + 0x0a, 0xd2, 0xa0, 0x2c, 0x14, 0xad, 0x8b, 0x61, 0xf3, 0xb4, 0xad, 0xe5, 0xd1, 0x43, 0x40, 0x52, + 0xd3, 0xed, 0x0f, 0x70, 0xb7, 0x39, 0x1c, 0x74, 0x2f, 0xce, 0xb5, 0x02, 0xda, 0x06, 0xed, 0x78, + 0x78, 0x36, 0x3c, 0x3d, 0x1a, 0x74, 0x5f, 0xc5, 0xf8, 0x35, 0xf4, 0x00, 0x2a, 0x19, 0xad, 0x24, + 0x59, 0x47, 0x3b, 0xf0, 0xbf, 0xac, 0x3a, 0xcb, 0x54, 0x44, 0x2a, 0x6c, 0xf4, 0x87, 0x67, 0x67, + 0x47, 0xf8, 0x4b, 0x6d, 0x43, 0x7f, 0x01, 0xa5, 0x38, 0x04, 0xa4, 0x41, 0xe1, 0x86, 0xcc, 0x65, + 0x39, 0xa2, 0xe3, 0x9b, 0xab, 0xa1, 0xff, 0xae, 0x00, 0xa4, 0x5d, 0x84, 0x8e, 0xe1, 0x3e, 0x65, + 0x66, 0xc0, 0x46, 0xc9, 0x9c, 0xc9, 0xa6, 0xaf, 0x19, 0x62, 0xd0, 0x8c, 0x78, 0xd0, 0x78, 0xef, + 0x71, 0x0b, 0xbc, 0xc5, 0x21, 0x89, 0x8c, 0x3e, 0x87, 0xb2, 0xa8, 0xc2, 0xcc, 0x9c, 0x86, 0x84, + 0x56, 0xf3, 0xff, 0xa0, 0x93, 0x79, 0x10, 0xaf, 0x22, 0x7b, 0xac, 0x4e, 0x93, 0x33, 0x45, 0xcf, + 0xa1, 0xe8, 0x7b, 0xb6, 0xcb, 0xe2, 0x79, 0xd0, 0x97, 0xb2, 0xf4, 0x22, 0x53, 0x2c, 0x11, 0xfa, + 0x67, 0x00, 0x29, 0x2d, 0xda, 0x86, 0x75, 0xee, 0x8f, 0xcc, 0x8f, 0x10, 0xd0, 0x0e, 0x6c, 0x5e, + 0x9b, 0x54, 0x78, 0xca, 0xf3, 0x53, 0xc2, 0xa5, 0x6b, 0x93, 0x72, 0x88, 0xfe, 0x6b, 0x1e, 0xd6, + 0x39, 0x25, 0x7a, 0x06, 0x9b, 0xab, 0x64, 0x24, 0x35, 0x46, 0xef, 0x82, 0x6a, 0xbb, 0xec, 0xc9, + 0xe3, 0xcc, 0x13, 0x85, 0x4e, 0x0e, 0x03, 0x57, 0x0a, 0xcf, 0xde, 0x83, 0xf2, 0xc4, 0x0b, 0xc7, + 0x53, 0x22, 0x6d, 0xa2, 0xc9, 0x50, 0x3a, 0x39, 0xac, 0x0a, 0xad, 0x30, 0x1a, 0x01, 0x9a, 0xd8, + 0x94, 0x05, 0xf6, 0x38, 0x8c, 0x0a, 0x27, 0x4d, 0xc5, 0x74, 0x1b, 0x4b, 0x93, 0xd2, 0xca, 0xc0, + 0x38, 0x57, 0x27, 0x87, 0x2b, 0x93, 0xbb, 0x4a, 0xd4, 0x83, 0x7b, 0x34, 0x74, 0x1c, 0x33, 0x98, + 0x4b, 0xee, 0x75, 0xce, 0xfd, 0x68, 0x29, 0x77, 0x5f, 0x20, 0x62, 0xda, 0x32, 0xcd, 0xc8, 0xcd, + 0x0d, 0x99, 0x71, 0xfd, 0xb7, 0x22, 0x54, 0x16, 0xbc, 0x88, 0x0a, 0x62, 0x79, 0xa1, 0xcb, 0x78, + 0x3e, 0x0b, 0x58, 0x08, 0x51, 0x13, 0xd3, 0xd0, 0xe1, 0x79, 0x52, 0x70, 0x74, 0x44, 0x4f, 0xa1, + 0x4a, 0x43, 0x67, 0xe4, 0x5d, 0x8e, 0xe8, 0xeb, 0xd0, 0x0c, 0xc8, 0x64, 0x34, 0x21, 0x33, 0xdb, + 0xe4, 0x1d, 0xcd, 0x53, 0x85, 0x1f, 0xd0, 0xd0, 0xb9, 0xb8, 0xec, 0x8b, 0xdb, 0x56, 0x7c, 0x89, + 0x2c, 0xd8, 0x1a, 0x87, 0xd6, 0x0d, 0x61, 0x23, 0x8f, 0x37, 0x3b, 0x95, 0xe9, 0xfa, 0x74, 0xb5, + 0x74, 0x19, 0x4d, 0x4e, 0x72, 0x21, 0x38, 0xf0, 0xbd, 0x71, 0x56, 0x44, 0x17, 0xb0, 0x21, 0x14, + 0xf1, 0xbe, 0xf9, 0xe4, 0xad, 0xd8, 0x71, 0xcc, 0x52, 0xfb, 0x49, 0x81, 0x7b, 0xb7, 0x5e, 0x44, + 0x16, 0x94, 0xc8, 0x77, 0xfe, 0xd4, 0xb6, 0x6c, 0x26, 0x7b, 0xaf, 0xfd, 0x6f, 0x22, 0x30, 0xda, + 0x92, 0xac, 0x93, 0xc3, 0x09, 0x71, 0x4d, 0x87, 0x52, 0xac, 0x47, 0x0f, 0xa1, 0x38, 0xf6, 0x42, + 0x77, 0x42, 0xab, 0xca, 0x5e, 0x61, 0x5f, 0xc1, 0x52, 0x6a, 0x16, 0xc5, 0x9a, 0xae, 0x51, 0x28, + 0x0a, 0xc6, 0xbf, 0xa9, 0x61, 0x3f, 0x72, 0x98, 0x38, 0xfe, 0xd4, 0x0c, 0x78, 0x21, 0xd5, 0xc6, + 0xd3, 0x15, 0x1d, 0x6e, 0x4b, 0x38, 0x4e, 0x88, 0x6a, 0xdf, 0xe7, 0x23, 0x0f, 0x85, 0x70, 0x7b, + 0x98, 0x95, 0x78, 0x98, 0x6f, 0x4d, 0x69, 0x7e, 0x95, 0x29, 0xfd, 0x06, 0x54, 0x93, 0x31, 0xd3, + 0xba, 0x76, 0x48, 0xba, 0x6b, 0x3a, 0x6f, 0xe9, 0xb4, 0x71, 0x94, 0x52, 0xb5, 0x5d, 0x16, 0xcc, + 0x71, 0x96, 0xbc, 0xf6, 0x02, 0xb4, 0xbb, 0x06, 0x7f, 0xb1, 0xba, 0x93, 0x08, 0xf3, 0x99, 0x75, + 0xf5, 0x3c, 0xff, 0x4c, 0xd1, 0xff, 0x28, 0x40, 0x39, 0x3b, 0x77, 0xe8, 0x30, 0x5b, 0x04, 0xb5, + 0xb1, 0xb3, 0x10, 0x72, 0x37, 0xd9, 0x35, 0x71, 0x85, 0x8c, 0x74, 0xca, 0xd4, 0xc6, 0xff, 0x17, + 0x00, 0xad, 0x74, 0xf1, 0x88, 0x19, 0x3c, 0x87, 0x12, 0x75, 0x4d, 0x9f, 0x5e, 0x7b, 0xe2, 0xc3, + 0xad, 0xbe, 0xe1, 0x23, 0x9d, 0xf5, 0xcf, 0xe8, 0x4b, 0x24, 0x4e, 0x38, 0x6a, 0xbf, 0xe4, 0xa1, + 0x14, 0xab, 0xff, 0x0b, 0xff, 0x5f, 0x43, 0xc5, 0x27, 0x81, 0x45, 0x5c, 0x66, 0xc7, 0x6b, 0x36, + 0xae, 0x72, 0x6b, 0xf5, 0x40, 0x0c, 0x2e, 0x1e, 0xb1, 0x5e, 0x42, 0x89, 0xb5, 0x94, 0x5e, 0x7c, + 0xb9, 0x6a, 0x5d, 0xa8, 0x2c, 0x98, 0xa1, 0x5d, 0x80, 0xd4, 0x50, 0x36, 0x6f, 0x46, 0x73, 0xbb, + 0xea, 0x71, 0x5f, 0x37, 0x67, 0xb0, 0x6b, 0x7b, 0xcb, 0xdc, 0x6c, 0x96, 0xc5, 0x5f, 0x11, 0xed, + 0x45, 0x17, 0x3d, 0xe5, 0xab, 0xd6, 0x95, 0xcd, 0xae, 0xc3, 0xb1, 0x61, 0x79, 0x4e, 0x5d, 0x60, + 0x0e, 0x6c, 0x97, 0xb2, 0x20, 0x8c, 0x7a, 0x8e, 0x6f, 0xc7, 0x7a, 0x4a, 0x77, 0x20, 0x7e, 0x8c, + 0xaf, 0x88, 0x7b, 0x70, 0x95, 0xfd, 0x51, 0x1f, 0x17, 0xf9, 0xc5, 0xc7, 0x7f, 0x06, 0x00, 0x00, + 0xff, 0xff, 0x24, 0xa6, 0x3d, 0x2b, 0xce, 0x0b, 0x00, 0x00, } diff --git a/vendor/github.com/census-instrumentation/opencensus-proto/gen-go/resource/v1/resource.pb.go b/vendor/github.com/census-instrumentation/opencensus-proto/gen-go/resource/v1/resource.pb.go index 38faa9fdf1e..560dbd94a07 100644 --- a/vendor/github.com/census-instrumentation/opencensus-proto/gen-go/resource/v1/resource.pb.go +++ b/vendor/github.com/census-instrumentation/opencensus-proto/gen-go/resource/v1/resource.pb.go @@ -18,7 +18,7 @@ var _ = math.Inf // is compatible with the proto package it is being compiled against. // A compilation error at this line likely means your copy of the // proto package needs to be updated. -const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package // Resource information. type Resource struct { diff --git a/vendor/github.com/spf13/pflag/bytes.go b/vendor/github.com/spf13/pflag/bytes.go index 12c58db9fe3..67d53045708 100644 --- a/vendor/github.com/spf13/pflag/bytes.go +++ b/vendor/github.com/spf13/pflag/bytes.go @@ -1,6 +1,7 @@ package pflag import ( + "encoding/base64" "encoding/hex" "fmt" "strings" @@ -9,10 +10,12 @@ import ( // BytesHex adapts []byte for use as a flag. Value of flag is HEX encoded type bytesHexValue []byte +// String implements pflag.Value.String. func (bytesHex bytesHexValue) String() string { return fmt.Sprintf("%X", []byte(bytesHex)) } +// Set implements pflag.Value.Set. func (bytesHex *bytesHexValue) Set(value string) error { bin, err := hex.DecodeString(strings.TrimSpace(value)) @@ -25,6 +28,7 @@ func (bytesHex *bytesHexValue) Set(value string) error { return nil } +// Type implements pflag.Value.Type. func (*bytesHexValue) Type() string { return "bytesHex" } @@ -103,3 +107,103 @@ func BytesHex(name string, value []byte, usage string) *[]byte { func BytesHexP(name, shorthand string, value []byte, usage string) *[]byte { return CommandLine.BytesHexP(name, shorthand, value, usage) } + +// BytesBase64 adapts []byte for use as a flag. Value of flag is Base64 encoded +type bytesBase64Value []byte + +// String implements pflag.Value.String. +func (bytesBase64 bytesBase64Value) String() string { + return base64.StdEncoding.EncodeToString([]byte(bytesBase64)) +} + +// Set implements pflag.Value.Set. +func (bytesBase64 *bytesBase64Value) Set(value string) error { + bin, err := base64.StdEncoding.DecodeString(strings.TrimSpace(value)) + + if err != nil { + return err + } + + *bytesBase64 = bin + + return nil +} + +// Type implements pflag.Value.Type. +func (*bytesBase64Value) Type() string { + return "bytesBase64" +} + +func newBytesBase64Value(val []byte, p *[]byte) *bytesBase64Value { + *p = val + return (*bytesBase64Value)(p) +} + +func bytesBase64ValueConv(sval string) (interface{}, error) { + + bin, err := base64.StdEncoding.DecodeString(sval) + if err == nil { + return bin, nil + } + + return nil, fmt.Errorf("invalid string being converted to Bytes: %s %s", sval, err) +} + +// GetBytesBase64 return the []byte value of a flag with the given name +func (f *FlagSet) GetBytesBase64(name string) ([]byte, error) { + val, err := f.getFlagType(name, "bytesBase64", bytesBase64ValueConv) + + if err != nil { + return []byte{}, err + } + + return val.([]byte), nil +} + +// BytesBase64Var defines an []byte flag with specified name, default value, and usage string. +// The argument p points to an []byte variable in which to store the value of the flag. +func (f *FlagSet) BytesBase64Var(p *[]byte, name string, value []byte, usage string) { + f.VarP(newBytesBase64Value(value, p), name, "", usage) +} + +// BytesBase64VarP is like BytesBase64Var, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) BytesBase64VarP(p *[]byte, name, shorthand string, value []byte, usage string) { + f.VarP(newBytesBase64Value(value, p), name, shorthand, usage) +} + +// BytesBase64Var defines an []byte flag with specified name, default value, and usage string. +// The argument p points to an []byte variable in which to store the value of the flag. +func BytesBase64Var(p *[]byte, name string, value []byte, usage string) { + CommandLine.VarP(newBytesBase64Value(value, p), name, "", usage) +} + +// BytesBase64VarP is like BytesBase64Var, but accepts a shorthand letter that can be used after a single dash. +func BytesBase64VarP(p *[]byte, name, shorthand string, value []byte, usage string) { + CommandLine.VarP(newBytesBase64Value(value, p), name, shorthand, usage) +} + +// BytesBase64 defines an []byte flag with specified name, default value, and usage string. +// The return value is the address of an []byte variable that stores the value of the flag. +func (f *FlagSet) BytesBase64(name string, value []byte, usage string) *[]byte { + p := new([]byte) + f.BytesBase64VarP(p, name, "", value, usage) + return p +} + +// BytesBase64P is like BytesBase64, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) BytesBase64P(name, shorthand string, value []byte, usage string) *[]byte { + p := new([]byte) + f.BytesBase64VarP(p, name, shorthand, value, usage) + return p +} + +// BytesBase64 defines an []byte flag with specified name, default value, and usage string. +// The return value is the address of an []byte variable that stores the value of the flag. +func BytesBase64(name string, value []byte, usage string) *[]byte { + return CommandLine.BytesBase64P(name, "", value, usage) +} + +// BytesBase64P is like BytesBase64, but accepts a shorthand letter that can be used after a single dash. +func BytesBase64P(name, shorthand string, value []byte, usage string) *[]byte { + return CommandLine.BytesBase64P(name, shorthand, value, usage) +} diff --git a/vendor/github.com/spf13/pflag/flag.go b/vendor/github.com/spf13/pflag/flag.go index 5eadc84e3c4..9beeda8ecca 100644 --- a/vendor/github.com/spf13/pflag/flag.go +++ b/vendor/github.com/spf13/pflag/flag.go @@ -925,13 +925,16 @@ func stripUnknownFlagValue(args []string) []string { } first := args[0] - if first[0] == '-' { + if len(first) > 0 && first[0] == '-' { //--unknown --next-flag ... return args } //--unknown arg ... (args will be arg ...) - return args[1:] + if len(args) > 1 { + return args[1:] + } + return nil } func (f *FlagSet) parseLongArg(s string, args []string, fn parseFunc) (a []string, err error) { @@ -990,11 +993,12 @@ func (f *FlagSet) parseLongArg(s string, args []string, fn parseFunc) (a []strin } func (f *FlagSet) parseSingleShortArg(shorthands string, args []string, fn parseFunc) (outShorts string, outArgs []string, err error) { + outArgs = args + if strings.HasPrefix(shorthands, "test.") { return } - outArgs = args outShorts = shorthands[1:] c := shorthands[0] diff --git a/vendor/github.com/spf13/pflag/string_to_int.go b/vendor/github.com/spf13/pflag/string_to_int.go new file mode 100644 index 00000000000..5ceda3965df --- /dev/null +++ b/vendor/github.com/spf13/pflag/string_to_int.go @@ -0,0 +1,149 @@ +package pflag + +import ( + "bytes" + "fmt" + "strconv" + "strings" +) + +// -- stringToInt Value +type stringToIntValue struct { + value *map[string]int + changed bool +} + +func newStringToIntValue(val map[string]int, p *map[string]int) *stringToIntValue { + ssv := new(stringToIntValue) + ssv.value = p + *ssv.value = val + return ssv +} + +// Format: a=1,b=2 +func (s *stringToIntValue) Set(val string) error { + ss := strings.Split(val, ",") + out := make(map[string]int, len(ss)) + for _, pair := range ss { + kv := strings.SplitN(pair, "=", 2) + if len(kv) != 2 { + return fmt.Errorf("%s must be formatted as key=value", pair) + } + var err error + out[kv[0]], err = strconv.Atoi(kv[1]) + if err != nil { + return err + } + } + if !s.changed { + *s.value = out + } else { + for k, v := range out { + (*s.value)[k] = v + } + } + s.changed = true + return nil +} + +func (s *stringToIntValue) Type() string { + return "stringToInt" +} + +func (s *stringToIntValue) String() string { + var buf bytes.Buffer + i := 0 + for k, v := range *s.value { + if i > 0 { + buf.WriteRune(',') + } + buf.WriteString(k) + buf.WriteRune('=') + buf.WriteString(strconv.Itoa(v)) + i++ + } + return "[" + buf.String() + "]" +} + +func stringToIntConv(val string) (interface{}, error) { + val = strings.Trim(val, "[]") + // An empty string would cause an empty map + if len(val) == 0 { + return map[string]int{}, nil + } + ss := strings.Split(val, ",") + out := make(map[string]int, len(ss)) + for _, pair := range ss { + kv := strings.SplitN(pair, "=", 2) + if len(kv) != 2 { + return nil, fmt.Errorf("%s must be formatted as key=value", pair) + } + var err error + out[kv[0]], err = strconv.Atoi(kv[1]) + if err != nil { + return nil, err + } + } + return out, nil +} + +// GetStringToInt return the map[string]int value of a flag with the given name +func (f *FlagSet) GetStringToInt(name string) (map[string]int, error) { + val, err := f.getFlagType(name, "stringToInt", stringToIntConv) + if err != nil { + return map[string]int{}, err + } + return val.(map[string]int), nil +} + +// StringToIntVar defines a string flag with specified name, default value, and usage string. +// The argument p points to a map[string]int variable in which to store the values of the multiple flags. +// The value of each argument will not try to be separated by comma +func (f *FlagSet) StringToIntVar(p *map[string]int, name string, value map[string]int, usage string) { + f.VarP(newStringToIntValue(value, p), name, "", usage) +} + +// StringToIntVarP is like StringToIntVar, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) StringToIntVarP(p *map[string]int, name, shorthand string, value map[string]int, usage string) { + f.VarP(newStringToIntValue(value, p), name, shorthand, usage) +} + +// StringToIntVar defines a string flag with specified name, default value, and usage string. +// The argument p points to a map[string]int variable in which to store the value of the flag. +// The value of each argument will not try to be separated by comma +func StringToIntVar(p *map[string]int, name string, value map[string]int, usage string) { + CommandLine.VarP(newStringToIntValue(value, p), name, "", usage) +} + +// StringToIntVarP is like StringToIntVar, but accepts a shorthand letter that can be used after a single dash. +func StringToIntVarP(p *map[string]int, name, shorthand string, value map[string]int, usage string) { + CommandLine.VarP(newStringToIntValue(value, p), name, shorthand, usage) +} + +// StringToInt defines a string flag with specified name, default value, and usage string. +// The return value is the address of a map[string]int variable that stores the value of the flag. +// The value of each argument will not try to be separated by comma +func (f *FlagSet) StringToInt(name string, value map[string]int, usage string) *map[string]int { + p := map[string]int{} + f.StringToIntVarP(&p, name, "", value, usage) + return &p +} + +// StringToIntP is like StringToInt, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) StringToIntP(name, shorthand string, value map[string]int, usage string) *map[string]int { + p := map[string]int{} + f.StringToIntVarP(&p, name, shorthand, value, usage) + return &p +} + +// StringToInt defines a string flag with specified name, default value, and usage string. +// The return value is the address of a map[string]int variable that stores the value of the flag. +// The value of each argument will not try to be separated by comma +func StringToInt(name string, value map[string]int, usage string) *map[string]int { + return CommandLine.StringToIntP(name, "", value, usage) +} + +// StringToIntP is like StringToInt, but accepts a shorthand letter that can be used after a single dash. +func StringToIntP(name, shorthand string, value map[string]int, usage string) *map[string]int { + return CommandLine.StringToIntP(name, shorthand, value, usage) +} diff --git a/vendor/github.com/spf13/pflag/string_to_string.go b/vendor/github.com/spf13/pflag/string_to_string.go new file mode 100644 index 00000000000..890a01afc03 --- /dev/null +++ b/vendor/github.com/spf13/pflag/string_to_string.go @@ -0,0 +1,160 @@ +package pflag + +import ( + "bytes" + "encoding/csv" + "fmt" + "strings" +) + +// -- stringToString Value +type stringToStringValue struct { + value *map[string]string + changed bool +} + +func newStringToStringValue(val map[string]string, p *map[string]string) *stringToStringValue { + ssv := new(stringToStringValue) + ssv.value = p + *ssv.value = val + return ssv +} + +// Format: a=1,b=2 +func (s *stringToStringValue) Set(val string) error { + var ss []string + n := strings.Count(val, "=") + switch n { + case 0: + return fmt.Errorf("%s must be formatted as key=value", val) + case 1: + ss = append(ss, strings.Trim(val, `"`)) + default: + r := csv.NewReader(strings.NewReader(val)) + var err error + ss, err = r.Read() + if err != nil { + return err + } + } + + out := make(map[string]string, len(ss)) + for _, pair := range ss { + kv := strings.SplitN(pair, "=", 2) + if len(kv) != 2 { + return fmt.Errorf("%s must be formatted as key=value", pair) + } + out[kv[0]] = kv[1] + } + if !s.changed { + *s.value = out + } else { + for k, v := range out { + (*s.value)[k] = v + } + } + s.changed = true + return nil +} + +func (s *stringToStringValue) Type() string { + return "stringToString" +} + +func (s *stringToStringValue) String() string { + records := make([]string, 0, len(*s.value)>>1) + for k, v := range *s.value { + records = append(records, k+"="+v) + } + + var buf bytes.Buffer + w := csv.NewWriter(&buf) + if err := w.Write(records); err != nil { + panic(err) + } + w.Flush() + return "[" + strings.TrimSpace(buf.String()) + "]" +} + +func stringToStringConv(val string) (interface{}, error) { + val = strings.Trim(val, "[]") + // An empty string would cause an empty map + if len(val) == 0 { + return map[string]string{}, nil + } + r := csv.NewReader(strings.NewReader(val)) + ss, err := r.Read() + if err != nil { + return nil, err + } + out := make(map[string]string, len(ss)) + for _, pair := range ss { + kv := strings.SplitN(pair, "=", 2) + if len(kv) != 2 { + return nil, fmt.Errorf("%s must be formatted as key=value", pair) + } + out[kv[0]] = kv[1] + } + return out, nil +} + +// GetStringToString return the map[string]string value of a flag with the given name +func (f *FlagSet) GetStringToString(name string) (map[string]string, error) { + val, err := f.getFlagType(name, "stringToString", stringToStringConv) + if err != nil { + return map[string]string{}, err + } + return val.(map[string]string), nil +} + +// StringToStringVar defines a string flag with specified name, default value, and usage string. +// The argument p points to a map[string]string variable in which to store the values of the multiple flags. +// The value of each argument will not try to be separated by comma +func (f *FlagSet) StringToStringVar(p *map[string]string, name string, value map[string]string, usage string) { + f.VarP(newStringToStringValue(value, p), name, "", usage) +} + +// StringToStringVarP is like StringToStringVar, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) StringToStringVarP(p *map[string]string, name, shorthand string, value map[string]string, usage string) { + f.VarP(newStringToStringValue(value, p), name, shorthand, usage) +} + +// StringToStringVar defines a string flag with specified name, default value, and usage string. +// The argument p points to a map[string]string variable in which to store the value of the flag. +// The value of each argument will not try to be separated by comma +func StringToStringVar(p *map[string]string, name string, value map[string]string, usage string) { + CommandLine.VarP(newStringToStringValue(value, p), name, "", usage) +} + +// StringToStringVarP is like StringToStringVar, but accepts a shorthand letter that can be used after a single dash. +func StringToStringVarP(p *map[string]string, name, shorthand string, value map[string]string, usage string) { + CommandLine.VarP(newStringToStringValue(value, p), name, shorthand, usage) +} + +// StringToString defines a string flag with specified name, default value, and usage string. +// The return value is the address of a map[string]string variable that stores the value of the flag. +// The value of each argument will not try to be separated by comma +func (f *FlagSet) StringToString(name string, value map[string]string, usage string) *map[string]string { + p := map[string]string{} + f.StringToStringVarP(&p, name, "", value, usage) + return &p +} + +// StringToStringP is like StringToString, but accepts a shorthand letter that can be used after a single dash. +func (f *FlagSet) StringToStringP(name, shorthand string, value map[string]string, usage string) *map[string]string { + p := map[string]string{} + f.StringToStringVarP(&p, name, shorthand, value, usage) + return &p +} + +// StringToString defines a string flag with specified name, default value, and usage string. +// The return value is the address of a map[string]string variable that stores the value of the flag. +// The value of each argument will not try to be separated by comma +func StringToString(name string, value map[string]string, usage string) *map[string]string { + return CommandLine.StringToStringP(name, "", value, usage) +} + +// StringToStringP is like StringToString, but accepts a shorthand letter that can be used after a single dash. +func StringToStringP(name, shorthand string, value map[string]string, usage string) *map[string]string { + return CommandLine.StringToStringP(name, shorthand, value, usage) +} From f763159a11df48340f938523d5c05239ed85c26b Mon Sep 17 00:00:00 2001 From: nachocano Date: Thu, 25 Apr 2019 13:40:36 -0700 Subject: [PATCH 211/221] removing broker ingress policies related stuff --- Gopkg.lock | 9 - cmd/broker/ingress/main.go | 76 ++--- config/200-broker-clusterrole.yaml | 17 - config/500-controller.yaml | 2 +- docs/registry/example_broker_policies.yaml | 36 -- docs/registry/example_eventtype.yaml | 2 +- pkg/apis/eventing/v1alpha1/broker_defaults.go | 7 +- .../eventing/v1alpha1/broker_defaults_test.go | 42 +-- pkg/apis/eventing/v1alpha1/broker_types.go | 9 - .../eventing/v1alpha1/broker_validation.go | 8 +- .../v1alpha1/broker_validation_test.go | 45 +-- pkg/apis/eventing/v1alpha1/eventtype_types.go | 6 +- .../eventing/v1alpha1/eventtype_validation.go | 14 +- .../v1alpha1/eventtype_validation_test.go | 75 +++- .../v1alpha1/zz_generated.deepcopy.go | 21 -- pkg/broker/ingress.go | 119 ------- pkg/broker/ingress_test.go | 159 --------- .../v1alpha1/broker/resources/ingress.go | 13 - pkg/utils/utils.go | 22 -- test/builders.go | 88 ----- test/crd.go | 1 - test/crd_checks.go | 45 --- test/e2e/e2e.go | 43 --- test/e2e/registry_test.go | 203 ----------- test/states.go | 22 -- third_party/VENDOR-LICENSE | 25 -- .../kelseyhightower/envconfig/LICENSE | 19 -- .../kelseyhightower/envconfig/doc.go | 8 - .../kelseyhightower/envconfig/env_os.go | 7 - .../kelseyhightower/envconfig/env_syscall.go | 7 - .../kelseyhightower/envconfig/envconfig.go | 319 ------------------ .../kelseyhightower/envconfig/usage.go | 158 --------- 32 files changed, 108 insertions(+), 1519 deletions(-) delete mode 100644 docs/registry/example_broker_policies.yaml delete mode 100644 pkg/broker/ingress.go delete mode 100644 pkg/broker/ingress_test.go delete mode 100644 test/e2e/registry_test.go delete mode 100644 vendor/github.com/kelseyhightower/envconfig/LICENSE delete mode 100644 vendor/github.com/kelseyhightower/envconfig/doc.go delete mode 100644 vendor/github.com/kelseyhightower/envconfig/env_os.go delete mode 100644 vendor/github.com/kelseyhightower/envconfig/env_syscall.go delete mode 100644 vendor/github.com/kelseyhightower/envconfig/envconfig.go delete mode 100644 vendor/github.com/kelseyhightower/envconfig/usage.go diff --git a/Gopkg.lock b/Gopkg.lock index 66f06646221..4a9d72ffbee 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -424,14 +424,6 @@ pruneopts = "NUT" revision = "f2b4162afba35581b6d4a50d3b8f34e33c144682" -[[projects]] - digest = "1:b8870bf2606dca65dc382f4cb8b7a434f17ff36a915451bda12788e9620be368" - name = "github.com/kelseyhightower/envconfig" - packages = ["."] - pruneopts = "NUT" - revision = "f611eb38b3875cc3bd991ca91c51d06446afa14c" - version = "v1.3.0" - [[projects]] digest = "1:57d04562d05dd4500ff1e7e47f2e62b9be0531388377a3b691a012ce70b210d5" name = "github.com/knative/pkg" @@ -1383,7 +1375,6 @@ "github.com/google/go-cmp/cmp", "github.com/google/go-cmp/cmp/cmpopts", "github.com/google/uuid", - "github.com/kelseyhightower/envconfig", "github.com/knative/pkg/apis", "github.com/knative/pkg/apis/duck", "github.com/knative/pkg/apis/duck/v1alpha1", diff --git a/cmd/broker/ingress/main.go b/cmd/broker/ingress/main.go index 726d75dda16..c406b9e406b 100644 --- a/cmd/broker/ingress/main.go +++ b/cmd/broker/ingress/main.go @@ -24,12 +24,12 @@ import ( "log" "net/http" "net/url" + "os" "reflect" "sync" "time" cloudevents "github.com/cloudevents/sdk-go" - "github.com/kelseyhightower/envconfig" eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" "github.com/knative/eventing/pkg/broker" "github.com/knative/eventing/pkg/provisioners" @@ -58,20 +58,6 @@ var ( wg sync.WaitGroup ) -type envConfig struct { - // Channel where to send the cloudevents. - Channel string `envconfig:"CHANNEL"` - - // Broker name for this ingress. - Broker string `envconfig:"BROKER" required:"true"` - - // Namespace of this ingress. - Namespace string `envconfig:"NAMESPACE" required:"true"` - - // To indicate whether the ingress should allow any event. - AllowAny bool `envconfig:"ALLOW_ANY" required:"true"` -} - func main() { logConfig := provisioners.NewLoggingConfig() logger := provisioners.NewProvisionerLoggerFromConfig(logConfig).Desugar() @@ -79,18 +65,9 @@ func main() { flag.Parse() crlog.SetLogger(crlog.ZapLogger(false)) - var env envConfig - if err := envconfig.Process("", &env); err != nil { - log.Fatal("Failed to process env var", zap.Error(err)) - } - logger.Info("Starting...") - namespace := env.Namespace - - mgr, err := manager.New(config.GetConfigOrDie(), manager.Options{ - Namespace: namespace, - }) + mgr, err := manager.New(config.GetConfigOrDie(), manager.Options{}) if err != nil { logger.Fatal("Error starting up.", zap.Error(err)) } @@ -99,32 +76,23 @@ func main() { logger.Fatal("Unable to add eventingv1alpha1 scheme", zap.Error(err)) } - brokerName := env.Broker + brokerName := getRequiredEnv("BROKER") channelURI := &url.URL{ Scheme: "http", - Host: env.Channel, + Host: getRequiredEnv("CHANNEL"), Path: "/", } - client := mgr.GetClient() - - policySpec := &eventingv1alpha1.IngressPolicySpec{ - AllowAny: env.AllowAny, - } - - ingressPolicy := broker.NewPolicy(logger, client, policySpec, namespace, brokerName, true) - ceClient, err := cloudevents.NewDefaultClient() if err != nil { logger.Fatal("Unable to create CE client", zap.Error(err)) } h := &handler{ - logger: logger, - ceClient: ceClient, - channelURI: channelURI, - brokerName: brokerName, - ingressPolicy: ingressPolicy, + logger: logger, + ceClient: ceClient, + channelURI: channelURI, + brokerName: brokerName, } // Run the event handler with the manager. @@ -178,12 +146,19 @@ func main() { logger.Info("Done.") } +func getRequiredEnv(envKey string) string { + val, defined := os.LookupEnv(envKey) + if !defined { + log.Fatalf("required environment variable not defined '%s'", envKey) + } + return val +} + type handler struct { - logger *zap.Logger - ceClient cloudevents.Client - channelURI *url.URL - brokerName string - ingressPolicy *broker.IngressPolicy + logger *zap.Logger + ceClient cloudevents.Client + channelURI *url.URL + brokerName string } func (h *handler) Start(stopCh <-chan struct{}) error { @@ -238,15 +213,10 @@ func (h *handler) serveHTTP(ctx context.Context, event cloudevents.Event, resp * return nil } - if h.allowEvent(ctx, event) { - ctx, _ = tag.New(ctx, tag.Insert(TagResult, "dispatched")) - return h.sendEvent(ctx, tctx, event) - } - return nil -} + // TODO Filter. -func (h *handler) allowEvent(ctx context.Context, event cloudevents.Event) bool { - return h.ingressPolicy.AllowEvent(ctx, event) + ctx, _ = tag.New(ctx, tag.Insert(TagResult, "dispatched")) + return h.sendEvent(ctx, tctx, event) } func (h *handler) sendEvent(ctx context.Context, tctx cloudevents.HTTPTransportContext, event cloudevents.Event) error { diff --git a/config/200-broker-clusterrole.yaml b/config/200-broker-clusterrole.yaml index 02dc2f7ed63..fc430c0dc8f 100644 --- a/config/200-broker-clusterrole.yaml +++ b/config/200-broker-clusterrole.yaml @@ -26,20 +26,3 @@ rules: - get - list - watch - ---- - -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: eventing-broker-ingress -rules: - - apiGroups: - - eventing.knative.dev - resources: - - eventtypes - - eventtypes/status - verbs: - - get - - list - - watch diff --git a/config/500-controller.yaml b/config/500-controller.yaml index 693e6193f06..2cb7d815c06 100644 --- a/config/500-controller.yaml +++ b/config/500-controller.yaml @@ -45,7 +45,7 @@ spec: - name: BROKER_INGRESS_IMAGE value: github.com/knative/eventing/cmd/broker/ingress - name: BROKER_INGRESS_SERVICE_ACCOUNT - value: eventing-broker-ingress + value: default - name: BROKER_FILTER_IMAGE value: github.com/knative/eventing/cmd/broker/filter - name: BROKER_FILTER_SERVICE_ACCOUNT diff --git a/docs/registry/example_broker_policies.yaml b/docs/registry/example_broker_policies.yaml deleted file mode 100644 index fedaeeb42b8..00000000000 --- a/docs/registry/example_broker_policies.yaml +++ /dev/null @@ -1,36 +0,0 @@ -# Copyright 2019 The Knative Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# This file is a list of example Brokers with different policies. Each could be used independently. - ---- - -# By not specifying an IngressPolicy, the default will accept any event. - -apiVersion: eventing.knative.dev/v1alpha1 -kind: Broker -metadata: - name: broker-allow-any - ---- - -# By setting the IngressPolicy to not allowAny, the broker will accept only events in the Registry. - -apiVersion: eventing.knative.dev/v1alpha1 -kind: Broker -metadata: - name: broker-allow-registered -spec: - ingressPolicy: - allowAny: false diff --git a/docs/registry/example_eventtype.yaml b/docs/registry/example_eventtype.yaml index 844fcf67f1b..bac0223ad35 100644 --- a/docs/registry/example_eventtype.yaml +++ b/docs/registry/example_eventtype.yaml @@ -25,7 +25,7 @@ spec: type: com.github.pull_request source: github.com broker: broker-allow-registered - description: "BitBucket Repo Push" + description: "GitHub Pull Request" --- diff --git a/pkg/apis/eventing/v1alpha1/broker_defaults.go b/pkg/apis/eventing/v1alpha1/broker_defaults.go index 388ee3e7aec..6351fea1a2c 100644 --- a/pkg/apis/eventing/v1alpha1/broker_defaults.go +++ b/pkg/apis/eventing/v1alpha1/broker_defaults.go @@ -23,10 +23,5 @@ func (b *Broker) SetDefaults(ctx context.Context) { } func (bs *BrokerSpec) SetDefaults(ctx context.Context) { - if bs.IngressPolicy == nil { - // Setting as default to allow any event. - bs.IngressPolicy = &IngressPolicySpec{ - AllowAny: true, - } - } + // None } diff --git a/pkg/apis/eventing/v1alpha1/broker_defaults_test.go b/pkg/apis/eventing/v1alpha1/broker_defaults_test.go index dcee2377dee..f8dc1302150 100644 --- a/pkg/apis/eventing/v1alpha1/broker_defaults_test.go +++ b/pkg/apis/eventing/v1alpha1/broker_defaults_test.go @@ -19,46 +19,10 @@ package v1alpha1 import ( "context" "testing" - - "github.com/google/go-cmp/cmp" ) +// No-op test because method does nothing. func TestBrokerDefaults(t *testing.T) { - testCases := map[string]struct { - initial Broker - expected Broker - }{ - "nil ingress": { - initial: Broker{}, - expected: Broker{ - Spec: BrokerSpec{ - IngressPolicy: &IngressPolicySpec{ - AllowAny: true, - }, - }, - }, - }, - "allow any not set": { - initial: Broker{ - Spec: BrokerSpec{ - IngressPolicy: &IngressPolicySpec{}, - }, - }, - expected: Broker{ - Spec: BrokerSpec{ - IngressPolicy: &IngressPolicySpec{ - AllowAny: false, - }, - }, - }, - }, - } - 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) - } - }) - } + b := Broker{} + b.SetDefaults(context.TODO()) } diff --git a/pkg/apis/eventing/v1alpha1/broker_types.go b/pkg/apis/eventing/v1alpha1/broker_types.go index 12c8995aeab..c6e6cd09c1b 100644 --- a/pkg/apis/eventing/v1alpha1/broker_types.go +++ b/pkg/apis/eventing/v1alpha1/broker_types.go @@ -55,15 +55,6 @@ type BrokerSpec struct { // // +optional ChannelTemplate *ChannelSpec `json:"channelTemplate,omitempty"` - - // IngressPolicy defines the Broker's policy regarding the events it can accept into the mesh or not. - // +optional - IngressPolicy *IngressPolicySpec `json:"ingressPolicy,omitempty"` -} - -type IngressPolicySpec struct { - // AllowAny, if set to true accepts any message into the mesh. If set to false, only allows pre-registered events. - AllowAny bool `json:"allowAny,omitempty"` } // BrokerStatus represents the current state of a Broker. diff --git a/pkg/apis/eventing/v1alpha1/broker_validation.go b/pkg/apis/eventing/v1alpha1/broker_validation.go index 72739a7e39d..483e1ffab83 100644 --- a/pkg/apis/eventing/v1alpha1/broker_validation.go +++ b/pkg/apis/eventing/v1alpha1/broker_validation.go @@ -27,13 +27,8 @@ func (b *Broker) Validate(ctx context.Context) *apis.FieldError { } func (bs *BrokerSpec) Validate(ctx context.Context) *apis.FieldError { - var errs *apis.FieldError - if bs.IngressPolicy == nil { - fe := apis.ErrMissingField("ingressPolicy") - errs = errs.Also(fe) - } // TODO validate that the channelTemplate only specifies the provisioner and arguments. - return errs + return nil } func (b *Broker) CheckImmutableFields(ctx context.Context, og apis.Immutable) *apis.FieldError { @@ -41,6 +36,5 @@ func (b *Broker) CheckImmutableFields(ctx context.Context, og apis.Immutable) *a // changing it will normally not have the desired effect of changing the Channel inside the // Broker. It would have an effect if the existing Channel was then deleted, the newly created // Channel would use the new spec.channelTemplate. - // Similar thing would happen with spec.ingressPolicy. return nil } diff --git a/pkg/apis/eventing/v1alpha1/broker_validation_test.go b/pkg/apis/eventing/v1alpha1/broker_validation_test.go index 795b4117cc0..9d737bf3173 100644 --- a/pkg/apis/eventing/v1alpha1/broker_validation_test.go +++ b/pkg/apis/eventing/v1alpha1/broker_validation_test.go @@ -19,51 +19,18 @@ package v1alpha1 import ( "context" "testing" - - "github.com/google/go-cmp/cmp" - "github.com/knative/pkg/apis" ) +// No-op test because method does nothing. func TestBrokerValidation(t *testing.T) { - name := "invalid ingress policy spec" - broker := &Broker{Spec: BrokerSpec{}} - - want := &apis.FieldError{ - Paths: []string{"spec.ingressPolicy"}, - Message: "missing field(s)", - } - - t.Run(name, func(t *testing.T) { - got := broker.Validate(context.TODO()) - if diff := cmp.Diff(want.Error(), got.Error()); diff != "" { - t.Errorf("Broker.Validate (-want, +got) = %v", diff) - } - }) + b := Broker{} + _ = b.Validate(context.TODO()) } +// No-op test because method does nothing. func TestBrokerSpecValidation(t *testing.T) { - tests := []struct { - name string - bs *BrokerSpec - want *apis.FieldError - }{{ - name: "invalid broker spec", - bs: &BrokerSpec{}, - want: func() *apis.FieldError { - fe := apis.ErrMissingField("ingressPolicy") - return fe - }(), - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - got := test.bs.Validate(context.TODO()) - if diff := cmp.Diff(test.want.Error(), got.Error()); diff != "" { - t.Errorf("%s: Validate BrokerSpec (-want, +got) = %v", test.name, diff) - } - }) - } + bs := BrokerSpec{} + _ = bs.Validate(context.TODO()) } // No-op test because method does nothing. diff --git a/pkg/apis/eventing/v1alpha1/eventtype_types.go b/pkg/apis/eventing/v1alpha1/eventtype_types.go index f688c6ebba2..74f2f658964 100644 --- a/pkg/apis/eventing/v1alpha1/eventtype_types.go +++ b/pkg/apis/eventing/v1alpha1/eventtype_types.go @@ -51,9 +51,9 @@ var _ webhook.GenericCRD = (*EventType)(nil) type EventTypeSpec struct { // Type represents the CloudEvents type. It is authoritative. Type string `json:"type"` - // Source is a valid URI, it represents the CloudEvents source. - Source string `json:"source,omitempty"` - // Schema is a valid URI, it represents the CloudEvents schema attribute. + // Source is a URI, it represents the CloudEvents source. + Source string `json:"source"` + // 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 string `json:"schema,omitempty"` diff --git a/pkg/apis/eventing/v1alpha1/eventtype_validation.go b/pkg/apis/eventing/v1alpha1/eventtype_validation.go index 279e586cadc..a162f7dc920 100644 --- a/pkg/apis/eventing/v1alpha1/eventtype_validation.go +++ b/pkg/apis/eventing/v1alpha1/eventtype_validation.go @@ -19,6 +19,8 @@ package v1alpha1 import ( "context" + "github.com/google/go-cmp/cmp/cmpopts" + "github.com/knative/pkg/apis" "github.com/knative/pkg/kmp" ) @@ -33,10 +35,16 @@ func (ets *EventTypeSpec) Validate(ctx context.Context) *apis.FieldError { fe := apis.ErrMissingField("type") errs = errs.Also(fe) } + if ets.Source == "" { + // TODO validate is a valid URI. + fe := apis.ErrMissingField("source") + errs = errs.Also(fe) + } if ets.Broker == "" { fe := apis.ErrMissingField("broker") errs = errs.Also(fe) } + // TODO validate Schema is a valid URI. return errs } @@ -50,8 +58,9 @@ func (et *EventType) CheckImmutableFields(ctx context.Context, og apis.Immutable return &apis.FieldError{Message: "The provided original was not an EventType"} } - // All fields immutable. - if diff, err := kmp.ShortDiff(original.Spec, et.Spec); err != nil { + // All but Description field immutable. + ignoreArguments := cmpopts.IgnoreFields(EventTypeSpec{}, "Description") + if diff, err := kmp.ShortDiff(original.Spec, et.Spec, ignoreArguments); err != nil { return &apis.FieldError{ Message: "Failed to diff EventType", Paths: []string{"spec"}, @@ -64,6 +73,5 @@ func (et *EventType) CheckImmutableFields(ctx context.Context, og apis.Immutable Details: diff, } } - return nil } diff --git a/pkg/apis/eventing/v1alpha1/eventtype_validation_test.go b/pkg/apis/eventing/v1alpha1/eventtype_validation_test.go index eaaa897ef14..142429fc826 100644 --- a/pkg/apis/eventing/v1alpha1/eventtype_validation_test.go +++ b/pkg/apis/eventing/v1alpha1/eventtype_validation_test.go @@ -25,11 +25,11 @@ import ( ) func TestEventTypeValidation(t *testing.T) { - name := "invalid type and broker" + name := "invalid type and source and broker" broker := &EventType{Spec: EventTypeSpec{}} want := &apis.FieldError{ - Paths: []string{"spec.type", "spec.broker"}, + Paths: []string{"spec.type", "spec.source", "spec.broker"}, Message: "missing field(s)", } @@ -50,22 +50,34 @@ func TestEventTypeSpecValidation(t *testing.T) { name: "invalid eventtype spec", ets: &EventTypeSpec{}, want: func() *apis.FieldError { - fe := apis.ErrMissingField("type", "broker") + fe := apis.ErrMissingField("type", "source", "broker") return fe }(), }, { name: "invalid eventtype type", ets: &EventTypeSpec{ + Source: "test-source", Broker: "test-broker", }, want: func() *apis.FieldError { fe := apis.ErrMissingField("type") return fe }(), + }, { + name: "invalid eventtype source", + ets: &EventTypeSpec{ + Type: "test-type", + Broker: "test-broker", + }, + want: func() *apis.FieldError { + fe := apis.ErrMissingField("source") + return fe + }(), }, { name: "invalid eventtype broker", ets: &EventTypeSpec{ - Type: "test-type", + Type: "test-type", + Source: "test-source", }, want: func() *apis.FieldError { fe := apis.ErrMissingField("broker") @@ -126,6 +138,7 @@ func TestEventTypeImmutableFields(t *testing.T) { current: &EventType{ Spec: EventTypeSpec{ Type: "test-type", + Source: "test-source", Broker: "test-broker", }, }, @@ -138,12 +151,14 @@ func TestEventTypeImmutableFields(t *testing.T) { current: &EventType{ Spec: EventTypeSpec{ Type: "test-type", + Source: "test-source", Broker: "test-broker", }, }, original: &EventType{ Spec: EventTypeSpec{ Type: "test-type", + Source: "test-source", Broker: "original-broker", }, }, @@ -160,12 +175,14 @@ func TestEventTypeImmutableFields(t *testing.T) { current: &EventType{ Spec: EventTypeSpec{ Type: "test-type", + Source: "test-source", Broker: "test-broker", }, }, original: &EventType{ Spec: EventTypeSpec{ Type: "original-type", + Source: "test-source", Broker: "test-broker", }, }, @@ -178,54 +195,78 @@ func TestEventTypeImmutableFields(t *testing.T) { `, }, }, { - name: "bad (schema change)", + name: "bad (source change)", current: &EventType{ Spec: EventTypeSpec{ Type: "test-type", + Source: "test-source", Broker: "test-broker", - Schema: "test-schema", }, }, original: &EventType{ Spec: EventTypeSpec{ Type: "test-type", + Source: "original-source", Broker: "test-broker", - Schema: "original-schema", }, }, want: &apis.FieldError{ Message: "Immutable fields changed (-old +new)", Paths: []string{"spec"}, - Details: `{v1alpha1.EventTypeSpec}.Schema: - -: "original-schema" - +: "test-schema" + Details: `{v1alpha1.EventTypeSpec}.Source: + -: "original-source" + +: "test-source" `, }, }, { - name: "bad (source change)", + name: "bad (schema change)", current: &EventType{ Spec: EventTypeSpec{ Type: "test-type", - Broker: "test-broker", Source: "test-source", + Broker: "test-broker", + Schema: "test-schema", }, }, original: &EventType{ Spec: EventTypeSpec{ Type: "test-type", + Source: "test-source", Broker: "test-broker", - Source: "original-source", + Schema: "original-schema", }, }, want: &apis.FieldError{ Message: "Immutable fields changed (-old +new)", Paths: []string{"spec"}, - Details: `{v1alpha1.EventTypeSpec}.Source: - -: "original-source" - +: "test-source" + Details: `{v1alpha1.EventTypeSpec}.Schema: + -: "original-schema" + +: "test-schema" `, }, - }} + }, { + name: "good (description change)", + current: &EventType{ + Spec: EventTypeSpec{ + Type: "test-type", + Source: "test-source", + Broker: "test-broker", + Schema: "test-schema", + Description: "test-description", + }, + }, + original: &EventType{ + Spec: EventTypeSpec{ + Type: "test-type", + Source: "test-source", + Broker: "test-broker", + Schema: "test-schema", + Description: "original-description", + }, + }, + want: nil, + }, + } for _, test := range tests { t.Run(test.name, func(t *testing.T) { diff --git a/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go index c796ceeaf6a..efddd131c82 100644 --- a/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go @@ -96,11 +96,6 @@ func (in *BrokerSpec) DeepCopyInto(out *BrokerSpec) { *out = new(ChannelSpec) (*in).DeepCopyInto(*out) } - if in.IngressPolicy != nil { - in, out := &in.IngressPolicy, &out.IngressPolicy - *out = new(IngressPolicySpec) - **out = **in - } return } @@ -441,22 +436,6 @@ func (in *EventTypeStatus) DeepCopy() *EventTypeStatus { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *IngressPolicySpec) DeepCopyInto(out *IngressPolicySpec) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IngressPolicySpec. -func (in *IngressPolicySpec) DeepCopy() *IngressPolicySpec { - if in == nil { - return nil - } - out := new(IngressPolicySpec) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ReplyStrategy) DeepCopyInto(out *ReplyStrategy) { *out = *in diff --git a/pkg/broker/ingress.go b/pkg/broker/ingress.go deleted file mode 100644 index 4c8a2bdb655..00000000000 --- a/pkg/broker/ingress.go +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright 2019 The Knative Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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 broker - -import ( - "context" - "strings" - - "go.uber.org/zap" - - "github.com/cloudevents/sdk-go/pkg/cloudevents" - - eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" - k8serrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -var ( - // EventType not found error. - notFound = k8serrors.NewNotFound(eventingv1alpha1.Resource("eventtype"), "") -) - -// IngressPolicy parses Cloud Events, determines if they pass the Broker's policy, and sends them downstream. -type IngressPolicy struct { - logger *zap.SugaredLogger - client client.Client - namespace string - broker string - spec *eventingv1alpha1.IngressPolicySpec - // This bool flag is for UT purposes only. - async bool -} - -// NewPolicy creates an IngressPolicy for a particular Broker. -func NewPolicy(logger *zap.Logger, client client.Client, spec *eventingv1alpha1.IngressPolicySpec, namespace, broker string, async bool) *IngressPolicy { - return &IngressPolicy{ - logger: logger.Sugar(), - client: client, - namespace: namespace, - broker: broker, - spec: spec, - async: async, - } -} - -// AllowEvent filters events based on the configured policy. -func (p *IngressPolicy) AllowEvent(ctx context.Context, event cloudevents.Event) bool { - // 1. If allowAny is set to true, then all events are allowed to enter the mesh. - // 2. If allowAny is set to false, then the event is only accepted if it's already in the Broker's registry. - if p.spec.AllowAny { - p.logger.Debugf("EventType %q received, Accept", event.Type()) - return true - } - return p.isRegistered(ctx, event) -} - -// isRegistered returns whether the EventType corresponding to the CloudEvent is available in the Registry. -func (p *IngressPolicy) isRegistered(ctx context.Context, event cloudevents.Event) bool { - _, err := p.getEventType(ctx, event) - if k8serrors.IsNotFound(err) { - p.logger.Debugf("EventType %q not found, Reject", event.Type()) - return false - } else if err != nil { - p.logger.Errorf("Error retrieving EventType %q, Reject: %v", event.Type(), err) - return false - } - p.logger.Debugf("EventType %q is registered, Accept", event.Type()) - return true -} - -// getEventType retrieves the EventType from the Registry for the given cloudevents.Event. -// If it is not found, it returns an error. -func (p *IngressPolicy) getEventType(ctx context.Context, event cloudevents.Event) (*eventingv1alpha1.EventType, error) { - opts := &client.ListOptions{ - Namespace: p.namespace, - // Set Raw because if we need to get more than one page, then we will put the continue token - // into opts.Raw.Continue. - // TODO filter by Broker label. - Raw: &metav1.ListOptions{}, - } - - for { - etl := &eventingv1alpha1.EventTypeList{} - err := p.client.List(ctx, opts, etl) - if err != nil { - return nil, err - } - for _, et := range etl.Items { - if et.Spec.Broker == p.broker { - // Matching on type, source, and schemaURL. - // Note that if we the CloudEvent comes with a very specific source (i.e., without the split of - // source and subject proposed in v0.3), the EventType most probably won't be there. - if strings.EqualFold(et.Spec.Type, event.Type()) && strings.EqualFold(et.Spec.Source, event.Source()) && strings.EqualFold(et.Spec.Schema, event.SchemaURL()) { - return &et, nil - } - } - } - if etl.Continue != "" { - opts.Raw.Continue = etl.Continue - } else { - return nil, notFound - } - } -} diff --git a/pkg/broker/ingress_test.go b/pkg/broker/ingress_test.go deleted file mode 100644 index 9dabb5585fc..00000000000 --- a/pkg/broker/ingress_test.go +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright 2019 The Knative Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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 broker - -import ( - "context" - "errors" - "fmt" - "net/url" - "testing" - - "sigs.k8s.io/controller-runtime/pkg/client" - - "go.uber.org/zap" - - "github.com/cloudevents/sdk-go/pkg/cloudevents" - "github.com/cloudevents/sdk-go/pkg/cloudevents/types" - eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" - controllertesting "github.com/knative/eventing/pkg/reconciler/testing" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/client-go/kubernetes/scheme" - "sigs.k8s.io/controller-runtime/pkg/client/fake" -) - -const ( - broker = "test-broker" - namespace = "test-namespace" - testType = "test-type" - otherType = "other-test-type" - testSource = "/test-source" -) - -func init() { - // Add types to scheme. - _ = eventingv1alpha1.AddToScheme(scheme.Scheme) -} - -func TestIngress(t *testing.T) { - - testCases := map[string]struct { - eventTypes []*eventingv1alpha1.EventType - mocks controllertesting.Mocks - event cloudevents.Event - policySpec *eventingv1alpha1.IngressPolicySpec - want bool - // TODO add wantPresent to check creation of an EventType. - }{ - "allow any, accept": { - policySpec: &eventingv1alpha1.IngressPolicySpec{ - AllowAny: true, - }, - event: makeCloudEvent(nil), - want: true, - }, - "allow registered, error listing types, reject": { - policySpec: &eventingv1alpha1.IngressPolicySpec{ - AllowAny: false, - }, - event: makeCloudEvent(nil), - mocks: controllertesting.Mocks{ - MockLists: []controllertesting.MockList{ - func(_ client.Client, _ context.Context, _ *client.ListOptions, _ runtime.Object) (controllertesting.MockHandled, error) { - return controllertesting.Handled, errors.New("error listing types") - }, - }, - }, - want: false, - }, - "allow registered, event not found, reject": { - policySpec: &eventingv1alpha1.IngressPolicySpec{ - AllowAny: false, - }, - event: makeCloudEvent(nil), - eventTypes: []*eventingv1alpha1.EventType{ - makeEventType(otherType, testSource), - }, - want: false, - }, - "allow registered, event registered, accept": { - policySpec: &eventingv1alpha1.IngressPolicySpec{ - AllowAny: false, - }, - event: makeCloudEvent(nil), - eventTypes: []*eventingv1alpha1.EventType{ - makeEventType(testType, testSource), - }, - want: true, - }, - } - for n, tc := range testCases { - t.Run(n, func(t *testing.T) { - - ctx := context.TODO() - objs := make([]runtime.Object, 0, len(tc.eventTypes)) - for _, et := range tc.eventTypes { - objs = append(objs, et) - } - - c := newClient(objs, tc.mocks) - policy := NewPolicy(zap.NewNop(), c, tc.policySpec, namespace, broker, false) - - got := policy.AllowEvent(ctx, tc.event) - - if tc.want != got { - t.Errorf("want %t, got %t", tc.want, got) - } - - }) - } -} - -func newClient(initial []runtime.Object, mocks controllertesting.Mocks) *controllertesting.MockClient { - innerClient := fake.NewFakeClient(initial...) - return controllertesting.NewMockClient(innerClient, mocks) -} - -func makeCloudEvent(extensions map[string]interface{}) cloudevents.Event { - return cloudevents.Event{ - Context: cloudevents.EventContextV02{ - Type: testType, - Source: types.URLRef{ - URL: url.URL{ - Path: testSource, - }, - }, - ContentType: cloudevents.StringOfApplicationJSON(), - Extensions: extensions, - }.AsV02(), - } -} - -func makeEventType(eventType, eventSource string) *eventingv1alpha1.EventType { - return &eventingv1alpha1.EventType{ - ObjectMeta: metav1.ObjectMeta{ - GenerateName: fmt.Sprintf("%s-", eventType), - Namespace: namespace, - }, - Spec: eventingv1alpha1.EventTypeSpec{ - Type: eventType, - Broker: broker, - Source: eventSource, - }, - } -} diff --git a/pkg/reconciler/v1alpha1/broker/resources/ingress.go b/pkg/reconciler/v1alpha1/broker/resources/ingress.go index 2910bb35ca8..5721d5654a2 100644 --- a/pkg/reconciler/v1alpha1/broker/resources/ingress.go +++ b/pkg/reconciler/v1alpha1/broker/resources/ingress.go @@ -18,7 +18,6 @@ package resources import ( "fmt" - "strconv" appsv1 "k8s.io/api/apps/v1" "k8s.io/apimachinery/pkg/util/intstr" @@ -84,18 +83,6 @@ func MakeIngress(args *IngressArgs) *appsv1.Deployment { Name: "BROKER", Value: args.Broker.Name, }, - { - Name: "ALLOW_ANY", - Value: strconv.FormatBool(args.Broker.Spec.IngressPolicy.AllowAny), - }, - { - Name: "NAMESPACE", - ValueFrom: &corev1.EnvVarSource{ - FieldRef: &corev1.ObjectFieldSelector{ - FieldPath: "metadata.namespace", - }, - }, - }, }, Ports: []corev1.ContainerPort{ { diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index ea067aaa43c..33482fc0523 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -20,11 +20,8 @@ import ( "bufio" "io" "os" - "regexp" "strings" "sync" - - "k8s.io/apimachinery/pkg/util/validation" ) const ( @@ -35,9 +32,6 @@ const ( var ( domainName string once sync.Once - - // Only allow alphanumeric, '-' or '.'. - validChars = regexp.MustCompile(`[^-\.a-z0-9]+`) ) // GetClusterDomainName returns cluster's domain name or an error @@ -73,19 +67,3 @@ func getClusterDomainName(r io.Reader) string { // For all abnormal cases return default domain name return defaultDomainName } - -// Converts 'name' to a valid DNS1123 subdomain, required for object names in K8s. -func ToDNS1123Subdomain(name string) string { - // If it is not a valid DNS1123 subdomain, make it a valid one. - if msgs := validation.IsDNS1123Subdomain(name); len(msgs) != 0 { - // If the length exceeds the max, cut it and leave some room for a potential generated UUID. - if len(name) > validation.DNS1123SubdomainMaxLength { - name = name[:validation.DNS1123SubdomainMaxLength-10] - } - name = strings.ToLower(name) - name = validChars.ReplaceAllString(name, "") - // Only start/end with alphanumeric. - name = strings.Trim(name, "-.") - } - return name -} diff --git a/test/builders.go b/test/builders.go index 84d0dbd1265..6b48b2f6f1e 100644 --- a/test/builders.go +++ b/test/builders.go @@ -81,91 +81,3 @@ func (b *TriggerBuilder) SubscriberSvc(svcName string) *TriggerBuilder { } return b } - -// Builder for broker objects. -type BrokerBuilder struct { - *eventingv1alpha1.Broker -} - -func NewBrokerBuilder(name, namespace string) *BrokerBuilder { - broker := &eventingv1alpha1.Broker{ - TypeMeta: metav1.TypeMeta{ - APIVersion: eventingv1alpha1.SchemeGroupVersion.String(), - Kind: "Broker", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: namespace, - }, - Spec: eventingv1alpha1.BrokerSpec{ - IngressPolicy: &eventingv1alpha1.IngressPolicySpec{ - AllowAny: true, - }, - }, - } - - return &BrokerBuilder{ - Broker: broker, - } -} - -func (b *BrokerBuilder) Build() *eventingv1alpha1.Broker { - return b.Broker.DeepCopy() -} - -func (b *BrokerBuilder) IngressPolicy(policy *eventingv1alpha1.IngressPolicySpec) *BrokerBuilder { - b.Broker.Spec.IngressPolicy = policy - return b -} - -// Builder for EventType objects. -type EventTypeBuilder struct { - *eventingv1alpha1.EventType -} - -func NewEventTypeBuilder(name, namespace string) *EventTypeBuilder { - eventType := &eventingv1alpha1.EventType{ - TypeMeta: metav1.TypeMeta{ - APIVersion: eventingv1alpha1.SchemeGroupVersion.String(), - Kind: "EventType", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: namespace, - }, - Spec: eventingv1alpha1.EventTypeSpec{ - Broker: "default", - Type: CloudEventDefaultType, - Source: CloudEventDefaultSource, - Schema: "", - }, - } - - return &EventTypeBuilder{ - EventType: eventType, - } -} - -func (b *EventTypeBuilder) Build() *eventingv1alpha1.EventType { - return b.EventType.DeepCopy() -} - -func (b *EventTypeBuilder) Type(eventType string) *EventTypeBuilder { - b.Spec.Type = eventType - return b -} - -func (b *EventTypeBuilder) Source(eventSource string) *EventTypeBuilder { - b.Spec.Source = eventSource - return b -} - -func (b *EventTypeBuilder) Broker(brokerName string) *EventTypeBuilder { - b.Spec.Broker = brokerName - return b -} - -func (b *EventTypeBuilder) Schema(schema string) *EventTypeBuilder { - b.Spec.Schema = schema - return b -} diff --git a/test/crd.go b/test/crd.go index 807977a2ff8..046532f5f7b 100644 --- a/test/crd.go +++ b/test/crd.go @@ -118,7 +118,6 @@ const ( CloudEventEncodingStructured = "structured" CloudEventDefaultEncoding = CloudEventEncodingBinary CloudEventDefaultType = "dev.knative.test.event" - CloudEventDefaultSource = "dev.knative.test.source" ) // EventSenderPod creates a Pod that sends a single event to the given address. diff --git a/test/crd_checks.go b/test/crd_checks.go index 574b45260a4..d165151b783 100644 --- a/test/crd_checks.go +++ b/test/crd_checks.go @@ -115,29 +115,6 @@ func WaitForTriggerState(client eventingclient.TriggerInterface, name string, in }) } -// WaitForEventTypeState polls the status of the EventType called name from client -// every interval until inState returns `true` indicating it is done, returns an -// error or timeout. desc will be used to name the metric that is emitted to -// track how long it took for name to get into the state checked by inState. -func WaitForEventTypeState(client eventingclient.EventTypeInterface, name string, inState func(r *eventingv1alpha1.EventType) (bool, error), desc string, timeout time.Duration) error { - metricName := fmt.Sprintf("WaitForEventTypeState/%s/%s", name, desc) - _, span := trace.StartSpan(context.Background(), metricName) - defer span.End() - - return wait.PollImmediate(interval, timeout, func() (bool, error) { - r, err := client.Get(name, metav1.GetOptions{}) - if k8serrors.IsNotFound(err) { - // Return false as we are not done yet. - // We swallow the error to keep on polling, - // as the event - return false, nil - } else if err != nil { - return true, err - } - return inState(r) - }) -} - // WaitForTriggersListState polls the status of the TriggerList // from client every interval until inState returns `true` indicating it // is done, returns an error or timeout. desc will be used to name the metric @@ -155,25 +132,3 @@ func WaitForTriggersListState(clients eventingclient.TriggerInterface, inState f return inState(t) }) } - -// WaitForEventTypeListState polls the status of the EventTypeList -// from client every interval until inState returns `true` indicating it -// is done, returns an error or timeout. desc will be used to name the metric -// that is emitted to track how long it took to get into the state checked by inState. -func WaitForEventTypeListState(clients eventingclient.EventTypeInterface, inState func(t *eventingv1alpha1.EventTypeList) (bool, error), desc string, timeout time.Duration) error { - metricName := fmt.Sprintf("WaitForEventTypeListState/%s", desc) - _, span := trace.StartSpan(context.Background(), metricName) - defer span.End() - - return wait.PollImmediate(interval, timeout, func() (bool, error) { - l, err := clients.List(metav1.ListOptions{}) - if err != nil { - return true, err - } - // If there are no items, then we return false as we are not done yet. - if len(l.Items) == 0 { - return false, nil - } - return inState(l) - }) -} diff --git a/test/e2e/e2e.go b/test/e2e/e2e.go index 10df14c18d6..f559c3935e6 100644 --- a/test/e2e/e2e.go +++ b/test/e2e/e2e.go @@ -249,17 +249,6 @@ func CreateTrigger(clients *test.Clients, trigger *v1alpha1.Trigger, logf loggin return nil } -// CreateEventType will create an EventType. -func CreateEventType(clients *test.Clients, eventType *v1alpha1.EventType, logf logging.FormatLogger, cleaner *test.Cleaner) error { - eventTypes := clients.Eventing.EventingV1alpha1().EventTypes(eventType.Namespace) - res, err := eventTypes.Create(eventType) - if err != nil { - return err - } - cleaner.Add(v1alpha1.SchemeGroupVersion.Group, v1alpha1.SchemeGroupVersion.Version, "eventtypes", eventType.Namespace, res.ObjectMeta.Name) - return nil -} - // WithTriggerReady creates a Trigger and waits until it is Ready. func WithTriggerReady(clients *test.Clients, trigger *v1alpha1.Trigger, logf logging.FormatLogger, cleaner *test.Cleaner) error { if err := CreateTrigger(clients, trigger, logf, cleaner); err != nil { @@ -280,29 +269,6 @@ func WithTriggerReady(clients *test.Clients, trigger *v1alpha1.Trigger, logf log return nil } -// WithEventTypeReady creates an EventType and waits until it is Ready. -func WithEventTypeReady(clients *test.Clients, eventType *v1alpha1.EventType, logf logging.FormatLogger, cleaner *test.Cleaner) error { - if err := CreateEventType(clients, eventType, logf, cleaner); err != nil { - return err - } - return WaitForEventTypeReady(clients, eventType) -} - -// WaitForEventTypeReady waits until the EventType is Ready. -func WaitForEventTypeReady(clients *test.Clients, eventType *v1alpha1.EventType) error { - eventTypes := clients.Eventing.EventingV1alpha1().EventTypes(eventType.Namespace) - if err := test.WaitForEventTypeState(eventTypes, eventType.Name, test.IsEventTypeReady, "EventTypeIsReady", time.Minute); err != nil { - return err - } - // Update the given object so they'll reflect the ready state. - updatedEventType, err := eventTypes.Get(eventType.Name, metav1.GetOptions{}) - if err != nil { - return err - } - updatedEventType.DeepCopyInto(eventType) - return nil -} - // CreateServiceAccount will create a service account. func CreateServiceAccount(clients *test.Clients, sa *corev1.ServiceAccount, _ logging.FormatLogger, cleaner *test.Cleaner) error { namespace := sa.Namespace @@ -484,15 +450,6 @@ func WaitForAllTriggersReady(clients *test.Clients, namespace string, logf loggi return nil } -// WaitForAllEventTypesReady will wait until all EventTypes in the given namespace are ready. -func WaitForAllEventTypesReady(clients *test.Clients, logf logging.FormatLogger, namespace string) error { - eventTypes := clients.Eventing.EventingV1alpha1().EventTypes(namespace) - if err := test.WaitForEventTypeListState(eventTypes, test.EventTypesReady, "EventTypeIsReady", timeout); err != nil { - return err - } - return nil -} - // CreateNamespaceIfNeeded creates a new namespace if it does not exist. func CreateNamespaceIfNeeded(t *testing.T, clients *test.Clients, namespace string, logf logging.FormatLogger) { nsSpec, err := clients.Kube.Kube.CoreV1().Namespaces().Get(namespace, metav1.GetOptions{}) diff --git a/test/e2e/registry_test.go b/test/e2e/registry_test.go deleted file mode 100644 index f012d1a82b5..00000000000 --- a/test/e2e/registry_test.go +++ /dev/null @@ -1,203 +0,0 @@ -// +build e2e - -/* -Copyright 2019 The Knative Authors -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT 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 e2e - -import ( - "fmt" - "testing" - "time" - - "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" - - "github.com/knative/eventing/test" - pkgTest "github.com/knative/pkg/test" - "k8s.io/apimachinery/pkg/util/uuid" -) - -// Helper to setup test data and expectations. -type testFixture struct { - ingressPolicy *v1alpha1.IngressPolicySpec - preRegisterEvent bool - wantEventDelivered bool - wantEventRegistered bool -} - -func TestRegistryBrokerAllowAnyAccept(t *testing.T) { - fixture := &testFixture{ - ingressPolicy: &v1alpha1.IngressPolicySpec{ - AllowAny: true, - }, - wantEventDelivered: true, - } - Registry(t, fixture) -} - -func TestRegistryBrokerAllowRegisteredAccept(t *testing.T) { - fixture := &testFixture{ - ingressPolicy: &v1alpha1.IngressPolicySpec{ - AllowAny: false, - }, - preRegisterEvent: true, - wantEventDelivered: true, - wantEventRegistered: true, - } - Registry(t, fixture) -} - -func TestRegistryBrokerAllowRegisteredNotAccept(t *testing.T) { - fixture := &testFixture{ - ingressPolicy: &v1alpha1.IngressPolicySpec{ - AllowAny: false, - }, - } - Registry(t, fixture) -} - -func TestRegistryBrokerAutoAddAccept(t *testing.T) { - fixture := &testFixture{ - ingressPolicy: &v1alpha1.IngressPolicySpec{ - AutoAdd: true, - }, - wantEventDelivered: true, - wantEventRegistered: true, - } - Registry(t, fixture) -} - -func Registry(t *testing.T, fixture *testFixture) { - clients, cleaner := Setup(t, t.Logf) - - ns, cleanupNS := CreateNamespaceIfNeeded(t, clients, t.Logf) - - defer cleanupNS() - defer TearDown(clients, cleaner, t.Logf) - - // Define the constants here to avoid conflicts with other e2e tests. - const ( - brokerName = "test-broker" - triggerName = "test-trigger" - eventTypeName = "test-eventtype" - subscriberName = "test-dumper" - waitTimeForBrokerPodsRunning = 30 * time.Second - ) - - t.Logf("Labeling Namespace %s", ns) - err := LabelNamespace(clients, t.Logf, map[string]string{"knative-eventing-injection": "enabled"}) - if err != nil { - t.Fatalf("Error labeling Namespace: %v", err) - } - t.Logf("Namespace %s labeled", ns) - - broker := test.NewBrokerBuilder(brokerName, ns). - IngressPolicy(fixture.ingressPolicy). - Build() - t.Logf("Creating and waiting for Broker %s ready", broker.Name) - err = WithBrokerReady(clients, broker, t.Logf, cleaner) - if err != nil { - t.Fatalf("Error creating and waiting for Broker ready: %v", err) - } - brokerUrl := fmt.Sprintf("http://%s", broker.Status.Address.Hostname) - t.Logf("Broker created and ready: %q", brokerUrl) - - t.Logf("Creating Subscriber Pod and Service") - selector := map[string]string{"e2etest": string(uuid.NewUUID())} - subscriberPod := test.EventLoggerPod(subscriberName, ns, selector) - subscriberSvc := test.Service(subscriberName, ns, selector) - subscriberPod, err = CreatePodAndServiceReady(clients, subscriberPod, subscriberSvc, ns, t.Logf, cleaner) - if err != nil { - t.Fatalf("Failed to create Subscriber Pod and Service, and get them ready: %v", err) - } - t.Logf("Subscriber Pod and Service created and ready") - - trigger := test.NewTriggerBuilder(triggerName, ns). - Broker(broker.Name). - SubscriberSvc(subscriberSvc.Name). - Build() - t.Logf("Creating and waiting for Trigger %s ready", trigger.Name) - err = WithTriggerReady(clients, trigger, t.Logf, cleaner) - if err != nil { - t.Fatalf("Error creating and waiting for Trigger ready: %v", err) - } - t.Logf("Trigger created and ready") - - eventType := test.NewEventTypeBuilder(eventTypeName, ns). - Broker(brokerName). - // use the default values for source, type and schema. - Build() - if fixture.preRegisterEvent { - t.Logf("Creating and waiting for EventType %s ready", eventType.Name) - err = WithEventTypeReady(clients, eventType, t.Logf, cleaner) - if err != nil { - t.Fatalf("Error creating and waiting for EventType ready: %v", err) - } - t.Logf("EventType created and ready") - } - - // We notice some crashLoopBacks in the Broker's filter and ingress pod creation. - // We then delay the creation of the sender pod in order not to miss the event. - t.Logf("Waiting for Broker's filter and ingress POD to become running") - time.Sleep(waitTimeForBrokerPodsRunning) - - body := fmt.Sprintf("Registry %s", uuid.NewUUID()) - cloudEvent := &test.CloudEvent{ - Source: test.CloudEventDefaultSource, - Type: test.CloudEventDefaultType, - Data: fmt.Sprintf(`{"msg":%q}`, body), - } - t.Logf("Creating Sender Pod") - senderPod := test.EventSenderPod("sender", ns, brokerUrl, cloudEvent) - if err := CreatePod(clients, senderPod, t.Logf, cleaner); err != nil { - t.Fatalf("Error creating event sender Pod: %v", err) - } - t.Logf("Sender Pod created. Waiting for it to be running") - if err := pkgTest.WaitForAllPodsRunning(clients.Kube, ns); err != nil { - t.Fatalf("Error waiting for Sender Pod to become running: %v", err) - } - t.Logf("Sender Pod running") - - if fixture.wantEventDelivered { - t.Logf("Verifying Event delivered") - if err := WaitForLogContents(clients, t.Logf, subscriberName, subscriberPod.Spec.Containers[0].Name, ns, []string{body}); err != nil { - t.Fatalf("Event not found in logs of Subscriber Pod %q: %v", subscriberName, err) - } - } else { - t.Logf("Verifying Event not delivered") - found, err := FindAnyLogContents(clients, t.Logf, subscriberName, subscriberPod.Spec.Containers[0].Name, ns, []string{body}) - if err != nil { - t.Fatalf("Failed querying to find log contents in Subscriber Pod %q: %v", subscriberName, err) - } - if found { - t.Fatalf("Unexpected event found in logs of Subscriber Pod %q", subscriberName) - } - } - - // As the EventType might have been auto-generated, we cannot query for the particular EventType - // with the name given by the constant eventTypeName. We just query for all of them, and see if all are ready. - err = WaitForAllEventTypesReady(clients, t.Logf, ns) - if fixture.wantEventRegistered { - t.Logf("Verifying Event registered") - if err != nil { - t.Fatalf("EventType %q not ready: %v", eventType.Name, err) - } - } else { - t.Logf("Verifying Event not registered") - if err == nil { - t.Fatalf("EventType %q registered and ready, but expected not to be", eventType.Name) - } - } -} diff --git a/test/states.go b/test/states.go index 7599f5717e8..a0466e5dc18 100644 --- a/test/states.go +++ b/test/states.go @@ -47,12 +47,6 @@ func IsTriggerReady(t *eventingv1alpha1.Trigger) (bool, error) { return t.Status.IsReady(), nil } -// IsEventTypeReady will check the status conditions of the EventType and -// return true if the EventType is ready. -func IsEventTypeReady(et *eventingv1alpha1.EventType) (bool, error) { - return et.Status.IsReady(), nil -} - // TriggersReady will check the status conditions of the trigger list and return true // if all triggers are Ready. func TriggersReady(triggerList *eventingv1alpha1.TriggerList) (bool, error) { @@ -69,22 +63,6 @@ func TriggersReady(triggerList *eventingv1alpha1.TriggerList) (bool, error) { return true, nil } -// EventTypesReady will check the status conditions of the EventTypeList and return true -// if all EventTypes are Ready. -func EventTypesReady(eventTypeList *eventingv1alpha1.EventTypeList) (bool, error) { - var names []string - for _, t := range eventTypeList.Items { - names = append(names, t.Name) - } - log.Printf("Checking event types: %v", names) - for _, eventType := range eventTypeList.Items { - if !eventType.Status.IsReady() { - return false, nil - } - } - return true, nil -} - // PodsRunning will check the status conditions of the pod list and return true // if all pods are Running. func PodsRunning(podList *corev1.PodList) (bool, error) { diff --git a/third_party/VENDOR-LICENSE b/third_party/VENDOR-LICENSE index 2a4f2a03a7b..dcf5fffc254 100644 --- a/third_party/VENDOR-LICENSE +++ b/third_party/VENDOR-LICENSE @@ -3454,31 +3454,6 @@ SOFTWARE. -=========================================================== -Import: github.com/knative/eventing/vendor/github.com/kelseyhightower/envconfig - -Copyright (c) 2013 Kelsey Hightower - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - - - =========================================================== Import: github.com/knative/eventing/vendor/github.com/knative/pkg diff --git a/vendor/github.com/kelseyhightower/envconfig/LICENSE b/vendor/github.com/kelseyhightower/envconfig/LICENSE deleted file mode 100644 index 4bfa7a84d81..00000000000 --- a/vendor/github.com/kelseyhightower/envconfig/LICENSE +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2013 Kelsey Hightower - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/vendor/github.com/kelseyhightower/envconfig/doc.go b/vendor/github.com/kelseyhightower/envconfig/doc.go deleted file mode 100644 index f28561cd1cb..00000000000 --- a/vendor/github.com/kelseyhightower/envconfig/doc.go +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) 2013 Kelsey Hightower. All rights reserved. -// Use of this source code is governed by the MIT License that can be found in -// the LICENSE file. - -// Package envconfig implements decoding of environment variables based on a user -// defined specification. A typical use is using environment variables for -// configuration settings. -package envconfig diff --git a/vendor/github.com/kelseyhightower/envconfig/env_os.go b/vendor/github.com/kelseyhightower/envconfig/env_os.go deleted file mode 100644 index a6a014a2b47..00000000000 --- a/vendor/github.com/kelseyhightower/envconfig/env_os.go +++ /dev/null @@ -1,7 +0,0 @@ -// +build appengine - -package envconfig - -import "os" - -var lookupEnv = os.LookupEnv diff --git a/vendor/github.com/kelseyhightower/envconfig/env_syscall.go b/vendor/github.com/kelseyhightower/envconfig/env_syscall.go deleted file mode 100644 index 9d98085b99f..00000000000 --- a/vendor/github.com/kelseyhightower/envconfig/env_syscall.go +++ /dev/null @@ -1,7 +0,0 @@ -// +build !appengine - -package envconfig - -import "syscall" - -var lookupEnv = syscall.Getenv diff --git a/vendor/github.com/kelseyhightower/envconfig/envconfig.go b/vendor/github.com/kelseyhightower/envconfig/envconfig.go deleted file mode 100644 index 892d74699f6..00000000000 --- a/vendor/github.com/kelseyhightower/envconfig/envconfig.go +++ /dev/null @@ -1,319 +0,0 @@ -// Copyright (c) 2013 Kelsey Hightower. All rights reserved. -// Use of this source code is governed by the MIT License that can be found in -// the LICENSE file. - -package envconfig - -import ( - "encoding" - "errors" - "fmt" - "reflect" - "regexp" - "strconv" - "strings" - "time" -) - -// ErrInvalidSpecification indicates that a specification is of the wrong type. -var ErrInvalidSpecification = errors.New("specification must be a struct pointer") - -// A ParseError occurs when an environment variable cannot be converted to -// the type required by a struct field during assignment. -type ParseError struct { - KeyName string - FieldName string - TypeName string - Value string - Err error -} - -// Decoder has the same semantics as Setter, but takes higher precedence. -// It is provided for historical compatibility. -type Decoder interface { - Decode(value string) error -} - -// Setter is implemented by types can self-deserialize values. -// Any type that implements flag.Value also implements Setter. -type Setter interface { - Set(value string) error -} - -func (e *ParseError) Error() string { - return fmt.Sprintf("envconfig.Process: assigning %[1]s to %[2]s: converting '%[3]s' to type %[4]s. details: %[5]s", e.KeyName, e.FieldName, e.Value, e.TypeName, e.Err) -} - -// varInfo maintains information about the configuration variable -type varInfo struct { - Name string - Alt string - Key string - Field reflect.Value - Tags reflect.StructTag -} - -// GatherInfo gathers information about the specified struct -func gatherInfo(prefix string, spec interface{}) ([]varInfo, error) { - expr := regexp.MustCompile("([^A-Z]+|[A-Z][^A-Z]+|[A-Z]+)") - s := reflect.ValueOf(spec) - - if s.Kind() != reflect.Ptr { - return nil, ErrInvalidSpecification - } - s = s.Elem() - if s.Kind() != reflect.Struct { - return nil, ErrInvalidSpecification - } - typeOfSpec := s.Type() - - // over allocate an info array, we will extend if needed later - infos := make([]varInfo, 0, s.NumField()) - for i := 0; i < s.NumField(); i++ { - f := s.Field(i) - ftype := typeOfSpec.Field(i) - if !f.CanSet() || ftype.Tag.Get("ignored") == "true" { - continue - } - - for f.Kind() == reflect.Ptr { - if f.IsNil() { - if f.Type().Elem().Kind() != reflect.Struct { - // nil pointer to a non-struct: leave it alone - break - } - // nil pointer to struct: create a zero instance - f.Set(reflect.New(f.Type().Elem())) - } - f = f.Elem() - } - - // Capture information about the config variable - info := varInfo{ - Name: ftype.Name, - Field: f, - Tags: ftype.Tag, - Alt: strings.ToUpper(ftype.Tag.Get("envconfig")), - } - - // Default to the field name as the env var name (will be upcased) - info.Key = info.Name - - // Best effort to un-pick camel casing as separate words - if ftype.Tag.Get("split_words") == "true" { - words := expr.FindAllStringSubmatch(ftype.Name, -1) - if len(words) > 0 { - var name []string - for _, words := range words { - name = append(name, words[0]) - } - - info.Key = strings.Join(name, "_") - } - } - if info.Alt != "" { - info.Key = info.Alt - } - if prefix != "" { - info.Key = fmt.Sprintf("%s_%s", prefix, info.Key) - } - info.Key = strings.ToUpper(info.Key) - infos = append(infos, info) - - if f.Kind() == reflect.Struct { - // honor Decode if present - if decoderFrom(f) == nil && setterFrom(f) == nil && textUnmarshaler(f) == nil { - innerPrefix := prefix - if !ftype.Anonymous { - innerPrefix = info.Key - } - - embeddedPtr := f.Addr().Interface() - embeddedInfos, err := gatherInfo(innerPrefix, embeddedPtr) - if err != nil { - return nil, err - } - infos = append(infos[:len(infos)-1], embeddedInfos...) - - continue - } - } - } - return infos, nil -} - -// Process populates the specified struct based on environment variables -func Process(prefix string, spec interface{}) error { - infos, err := gatherInfo(prefix, spec) - - for _, info := range infos { - - // `os.Getenv` cannot differentiate between an explicitly set empty value - // and an unset value. `os.LookupEnv` is preferred to `syscall.Getenv`, - // but it is only available in go1.5 or newer. We're using Go build tags - // here to use os.LookupEnv for >=go1.5 - value, ok := lookupEnv(info.Key) - if !ok && info.Alt != "" { - value, ok = lookupEnv(info.Alt) - } - - def := info.Tags.Get("default") - if def != "" && !ok { - value = def - } - - req := info.Tags.Get("required") - if !ok && def == "" { - if req == "true" { - return fmt.Errorf("required key %s missing value", info.Key) - } - continue - } - - err := processField(value, info.Field) - if err != nil { - return &ParseError{ - KeyName: info.Key, - FieldName: info.Name, - TypeName: info.Field.Type().String(), - Value: value, - Err: err, - } - } - } - - return err -} - -// MustProcess is the same as Process but panics if an error occurs -func MustProcess(prefix string, spec interface{}) { - if err := Process(prefix, spec); err != nil { - panic(err) - } -} - -func processField(value string, field reflect.Value) error { - typ := field.Type() - - decoder := decoderFrom(field) - if decoder != nil { - return decoder.Decode(value) - } - // look for Set method if Decode not defined - setter := setterFrom(field) - if setter != nil { - return setter.Set(value) - } - - if t := textUnmarshaler(field); t != nil { - return t.UnmarshalText([]byte(value)) - } - - if typ.Kind() == reflect.Ptr { - typ = typ.Elem() - if field.IsNil() { - field.Set(reflect.New(typ)) - } - field = field.Elem() - } - - switch typ.Kind() { - case reflect.String: - field.SetString(value) - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - var ( - val int64 - err error - ) - if field.Kind() == reflect.Int64 && typ.PkgPath() == "time" && typ.Name() == "Duration" { - var d time.Duration - d, err = time.ParseDuration(value) - val = int64(d) - } else { - val, err = strconv.ParseInt(value, 0, typ.Bits()) - } - if err != nil { - return err - } - - field.SetInt(val) - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - val, err := strconv.ParseUint(value, 0, typ.Bits()) - if err != nil { - return err - } - field.SetUint(val) - case reflect.Bool: - val, err := strconv.ParseBool(value) - if err != nil { - return err - } - field.SetBool(val) - case reflect.Float32, reflect.Float64: - val, err := strconv.ParseFloat(value, typ.Bits()) - if err != nil { - return err - } - field.SetFloat(val) - case reflect.Slice: - vals := strings.Split(value, ",") - sl := reflect.MakeSlice(typ, len(vals), len(vals)) - for i, val := range vals { - err := processField(val, sl.Index(i)) - if err != nil { - return err - } - } - field.Set(sl) - case reflect.Map: - pairs := strings.Split(value, ",") - mp := reflect.MakeMap(typ) - for _, pair := range pairs { - kvpair := strings.Split(pair, ":") - if len(kvpair) != 2 { - return fmt.Errorf("invalid map item: %q", pair) - } - k := reflect.New(typ.Key()).Elem() - err := processField(kvpair[0], k) - if err != nil { - return err - } - v := reflect.New(typ.Elem()).Elem() - err = processField(kvpair[1], v) - if err != nil { - return err - } - mp.SetMapIndex(k, v) - } - field.Set(mp) - } - - return nil -} - -func interfaceFrom(field reflect.Value, fn func(interface{}, *bool)) { - // it may be impossible for a struct field to fail this check - if !field.CanInterface() { - return - } - var ok bool - fn(field.Interface(), &ok) - if !ok && field.CanAddr() { - fn(field.Addr().Interface(), &ok) - } -} - -func decoderFrom(field reflect.Value) (d Decoder) { - interfaceFrom(field, func(v interface{}, ok *bool) { d, *ok = v.(Decoder) }) - return d -} - -func setterFrom(field reflect.Value) (s Setter) { - interfaceFrom(field, func(v interface{}, ok *bool) { s, *ok = v.(Setter) }) - return s -} - -func textUnmarshaler(field reflect.Value) (t encoding.TextUnmarshaler) { - interfaceFrom(field, func(v interface{}, ok *bool) { t, *ok = v.(encoding.TextUnmarshaler) }) - return t -} diff --git a/vendor/github.com/kelseyhightower/envconfig/usage.go b/vendor/github.com/kelseyhightower/envconfig/usage.go deleted file mode 100644 index 184635380f2..00000000000 --- a/vendor/github.com/kelseyhightower/envconfig/usage.go +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright (c) 2016 Kelsey Hightower and others. All rights reserved. -// Use of this source code is governed by the MIT License that can be found in -// the LICENSE file. - -package envconfig - -import ( - "encoding" - "fmt" - "io" - "os" - "reflect" - "strconv" - "strings" - "text/tabwriter" - "text/template" -) - -const ( - // DefaultListFormat constant to use to display usage in a list format - DefaultListFormat = `This application is configured via the environment. The following environment -variables can be used: -{{range .}} -{{usage_key .}} - [description] {{usage_description .}} - [type] {{usage_type .}} - [default] {{usage_default .}} - [required] {{usage_required .}}{{end}} -` - // DefaultTableFormat constant to use to display usage in a tabluar format - DefaultTableFormat = `This application is configured via the environment. The following environment -variables can be used: - -KEY TYPE DEFAULT REQUIRED DESCRIPTION -{{range .}}{{usage_key .}} {{usage_type .}} {{usage_default .}} {{usage_required .}} {{usage_description .}} -{{end}}` -) - -var ( - decoderType = reflect.TypeOf((*Decoder)(nil)).Elem() - setterType = reflect.TypeOf((*Setter)(nil)).Elem() - unmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem() -) - -func implementsInterface(t reflect.Type) bool { - return t.Implements(decoderType) || - reflect.PtrTo(t).Implements(decoderType) || - t.Implements(setterType) || - reflect.PtrTo(t).Implements(setterType) || - t.Implements(unmarshalerType) || - reflect.PtrTo(t).Implements(unmarshalerType) -} - -// toTypeDescription converts Go types into a human readable description -func toTypeDescription(t reflect.Type) string { - switch t.Kind() { - case reflect.Array, reflect.Slice: - return fmt.Sprintf("Comma-separated list of %s", toTypeDescription(t.Elem())) - case reflect.Map: - return fmt.Sprintf( - "Comma-separated list of %s:%s pairs", - toTypeDescription(t.Key()), - toTypeDescription(t.Elem()), - ) - case reflect.Ptr: - return toTypeDescription(t.Elem()) - case reflect.Struct: - if implementsInterface(t) && t.Name() != "" { - return t.Name() - } - return "" - case reflect.String: - name := t.Name() - if name != "" && name != "string" { - return name - } - return "String" - case reflect.Bool: - name := t.Name() - if name != "" && name != "bool" { - return name - } - return "True or False" - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - name := t.Name() - if name != "" && !strings.HasPrefix(name, "int") { - return name - } - return "Integer" - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - name := t.Name() - if name != "" && !strings.HasPrefix(name, "uint") { - return name - } - return "Unsigned Integer" - case reflect.Float32, reflect.Float64: - name := t.Name() - if name != "" && !strings.HasPrefix(name, "float") { - return name - } - return "Float" - } - return fmt.Sprintf("%+v", t) -} - -// Usage writes usage information to stderr using the default header and table format -func Usage(prefix string, spec interface{}) error { - // The default is to output the usage information as a table - // Create tabwriter instance to support table output - tabs := tabwriter.NewWriter(os.Stdout, 1, 0, 4, ' ', 0) - - err := Usagef(prefix, spec, tabs, DefaultTableFormat) - tabs.Flush() - return err -} - -// Usagef writes usage information to the specified io.Writer using the specifed template specification -func Usagef(prefix string, spec interface{}, out io.Writer, format string) error { - - // Specify the default usage template functions - functions := template.FuncMap{ - "usage_key": func(v varInfo) string { return v.Key }, - "usage_description": func(v varInfo) string { return v.Tags.Get("desc") }, - "usage_type": func(v varInfo) string { return toTypeDescription(v.Field.Type()) }, - "usage_default": func(v varInfo) string { return v.Tags.Get("default") }, - "usage_required": func(v varInfo) (string, error) { - req := v.Tags.Get("required") - if req != "" { - reqB, err := strconv.ParseBool(req) - if err != nil { - return "", err - } - if reqB { - req = "true" - } - } - return req, nil - }, - } - - tmpl, err := template.New("envconfig").Funcs(functions).Parse(format) - if err != nil { - return err - } - - return Usaget(prefix, spec, out, tmpl) -} - -// Usaget writes usage information to the specified io.Writer using the specified template -func Usaget(prefix string, spec interface{}, out io.Writer, tmpl *template.Template) error { - // gather first - infos, err := gatherInfo(prefix, spec) - if err != nil { - return err - } - - return tmpl.Execute(out, infos) -} From 2728f9f57609aad4518162549e356b993ae26922 Mon Sep 17 00:00:00 2001 From: nachocano Date: Thu, 25 Apr 2019 14:05:31 -0700 Subject: [PATCH 212/221] adding eventType controller --- cmd/controller/main.go | 11 +- pkg/reconciler/eventtype/eventtype.go | 192 ++++++++++++++ .../eventtype/eventtype_test.go | 0 .../v1alpha1/eventtype/eventtype.go | 243 ------------------ 4 files changed, 202 insertions(+), 244 deletions(-) create mode 100644 pkg/reconciler/eventtype/eventtype.go rename pkg/reconciler/{v1alpha1 => }/eventtype/eventtype_test.go (100%) delete mode 100644 pkg/reconciler/v1alpha1/eventtype/eventtype.go diff --git a/cmd/controller/main.go b/cmd/controller/main.go index 8bbdc8d81c3..1addab462cd 100644 --- a/cmd/controller/main.go +++ b/cmd/controller/main.go @@ -21,6 +21,8 @@ import ( "log" "os" + "github.com/knative/eventing/pkg/reconciler/eventtype" + kubeinformers "k8s.io/client-go/informers" "k8s.io/client-go/rest" @@ -67,7 +69,7 @@ func main() { logger.Info("Starting the controller") - const numControllers = 5 + const numControllers = 6 cfg.QPS = numControllers * rest.DefaultQPS cfg.Burst = numControllers * rest.DefaultBurst opt := reconciler.NewOptionsOrDie(cfg, logger, stopCh) @@ -80,6 +82,7 @@ func main() { channelInformer := eventingInformerFactory.Eventing().V1alpha1().Channels() subscriptionInformer := eventingInformerFactory.Eventing().V1alpha1().Subscriptions() brokerInformer := eventingInformerFactory.Eventing().V1alpha1().Brokers() + eventTypeInformer := eventingInformerFactory.Eventing().V1alpha1().EventTypes() // Kube serviceInformer := kubeInformerFactory.Core().V1().Services() @@ -125,6 +128,11 @@ func main() { FilterServiceAccountName: getRequiredEnv("BROKER_FILTER_SERVICE_ACCOUNT"), }, ), + eventtype.NewController( + opt, + eventTypeInformer, + brokerInformer, + ), } if len(controllers) != numControllers { logger.Fatalf("Number of controllers and QPS settings mismatch: %d != %d", len(controllers), numControllers) @@ -147,6 +155,7 @@ func main() { channelInformer.Informer(), subscriptionInformer.Informer(), triggerInformer.Informer(), + eventTypeInformer.Informer(), // Kube configMapInformer.Informer(), serviceInformer.Informer(), diff --git a/pkg/reconciler/eventtype/eventtype.go b/pkg/reconciler/eventtype/eventtype.go new file mode 100644 index 00000000000..173c01529fd --- /dev/null +++ b/pkg/reconciler/eventtype/eventtype.go @@ -0,0 +1,192 @@ +/* +Copyright 2019 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT 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 eventtype + +import ( + "context" + "fmt" + "reflect" + "time" + + "k8s.io/client-go/tools/cache" + + "github.com/knative/pkg/controller" + + "github.com/knative/eventing/pkg/reconciler" + + "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" + eventinginformers "github.com/knative/eventing/pkg/client/informers/externalversions/eventing/v1alpha1" + listers "github.com/knative/eventing/pkg/client/listers/eventing/v1alpha1" + "github.com/knative/eventing/pkg/logging" + "go.uber.org/zap" + corev1 "k8s.io/api/core/v1" + apierrs "k8s.io/apimachinery/pkg/api/errors" +) + +const ( + // ReconcilerName is the name of the reconciler. + ReconcilerName = "EventTypes" + // controllerAgentName is the string used by this controller to identify + // itself when creating events. + controllerAgentName = "eventtype-controller" + + // Name of the corev1.Events emitted from the reconciliation process. + eventTypeReadinessChanged = "EventTypeReadinessChanged" + eventTypeReconcileFailed = "EventTypeReconcileFailed" + eventTypeUpdateStatusFailed = "EventTypeUpdateStatusFailed" +) + +type Reconciler struct { + *reconciler.Base + + // listers index properties about resources + eventTypeLister listers.EventTypeLister + brokerLister listers.BrokerLister +} + +// Check that our Reconciler implements controller.Reconciler +var _ controller.Reconciler = (*Reconciler)(nil) + +// NewController initializes the controller and is called by the generated code +// Registers event handlers to enqueue events +func NewController( + opt reconciler.Options, + eventTypeInformer eventinginformers.EventTypeInformer, + brokerInformer eventinginformers.BrokerInformer, +) *controller.Impl { + + r := &Reconciler{ + Base: reconciler.NewBase(opt, controllerAgentName), + brokerLister: brokerInformer.Lister(), + } + impl := controller.NewImpl(r, r.Logger, ReconcilerName, reconciler.MustNewStatsReporter(ReconcilerName, r.Logger)) + + r.Logger.Info("Setting up event handlers") + eventTypeInformer.Informer().AddEventHandler(reconciler.Handler(impl.Enqueue)) + + // TODO Watch for Broker changes. E.g. if the Broker is deleted, we need to reconcile its EventTypes again. + + return impl +} + +// Reconcile compares the actual state with the desired, and attempts to +// converge the two. It then updates the Status block of the EventType resource +// with the current status of the resource. +func (r *Reconciler) Reconcile(ctx context.Context, key string) error { + // Convert the namespace/name string into a distinct namespace and name + namespace, name, err := cache.SplitMetaNamespaceKey(key) + if err != nil { + r.Logger.Errorf("invalid resource key: %s", key) + return nil + } + ctx = logging.WithLogger(ctx, r.Logger.Desugar().With(zap.String("key", key))) + + // Get the EventType resource with this namespace/name + original, err := r.eventTypeLister.EventTypes(namespace).Get(name) + if apierrs.IsNotFound(err) { + // The resource may no longer exist, in which case we stop processing. + logging.FromContext(ctx).Info("eventType key in work queue no longer exists") + return nil + } else if err != nil { + return err + } + + // Don't modify the informers copy + eventType := original.DeepCopy() + + // Reconcile this copy of the EventType and then write back any status + // updates regardless of whether the reconcile error out. + reconcileErr := r.reconcile(ctx, eventType) + if reconcileErr != nil { + logging.FromContext(ctx).Warn("Error reconciling Broker", zap.Error(err)) + r.Recorder.Eventf(eventType, corev1.EventTypeWarning, eventTypeReconcileFailed, fmt.Sprintf("EventType reconcile error: %v", reconcileErr)) + } else { + logging.FromContext(ctx).Debug("EventType reconciled") + } + + if _, err = r.updateStatus(ctx, eventType); err != nil { + logging.FromContext(ctx).Warn("Failed to update the EventType status", zap.Error(err)) + r.Recorder.Eventf(eventType, corev1.EventTypeWarning, eventTypeUpdateStatusFailed, "Failed to update Broker's status: %v", err) + return err + } + + // Requeue if the resource is not ready: + return reconcileErr +} + +func (r *Reconciler) reconcile(ctx context.Context, et *v1alpha1.EventType) error { + et.Status.InitializeConditions() + + // 1. Verify the Broker exists. + // 2. Verify the Broker is ready. + + if et.DeletionTimestamp != nil { + // Everything is cleaned up by the garbage collector. + return nil + } + + b, err := r.getBroker(ctx, et) + if err != nil { + logging.FromContext(ctx).Error("Unable to get the Broker", zap.Error(err)) + et.Status.MarkBrokerDoesNotExist() + return nil + } + et.Status.MarkBrokerExists() + + if !b.Status.IsReady() { + logging.FromContext(ctx).Error("Broker is not ready", zap.String("broker", b.Name)) + et.Status.MarkBrokerNotReady() + return nil + } + et.Status.MarkBrokerReady() + + return nil +} + +// updateStatus updates the EventType's status. +func (r *Reconciler) updateStatus(ctx context.Context, desired *v1alpha1.EventType) (*v1alpha1.EventType, error) { + eventType, err := r.eventTypeLister.EventTypes(desired.Namespace).Get(desired.Name) + if err != nil { + return nil, err + } + + // If there's nothing to update, just return. + if reflect.DeepEqual(eventType.Status, desired.Status) { + return eventType, nil + } + + becomesReady := desired.Status.IsReady() && !eventType.Status.IsReady() + + // Don't modify the informers copy. + existing := eventType.DeepCopy() + existing.Status = desired.Status + + et, err := r.EventingClientSet.EventingV1alpha1().EventTypes(desired.Namespace).UpdateStatus(existing) + if err == nil && becomesReady { + duration := time.Since(et.ObjectMeta.CreationTimestamp.Time) + logging.FromContext(ctx).Sugar().Infof("EventType %q became ready after %v", eventType.Name, duration) + r.Recorder.Event(eventType, corev1.EventTypeNormal, eventTypeReadinessChanged, fmt.Sprintf("EventType %q became ready", eventType.Name)) + //r.StatsReporter.ReportServiceReady(eventType.Namespace, eventType.Name, duration) // TODO: stats + } + + return et, err +} + +// getBroker returns the Broker for EventType 'et' if it exists, otherwise it returns an error. +func (r *Reconciler) getBroker(ctx context.Context, et *v1alpha1.EventType) (*v1alpha1.Broker, error) { + return r.brokerLister.Brokers(et.Namespace).Get(et.Spec.Broker) +} diff --git a/pkg/reconciler/v1alpha1/eventtype/eventtype_test.go b/pkg/reconciler/eventtype/eventtype_test.go similarity index 100% rename from pkg/reconciler/v1alpha1/eventtype/eventtype_test.go rename to pkg/reconciler/eventtype/eventtype_test.go diff --git a/pkg/reconciler/v1alpha1/eventtype/eventtype.go b/pkg/reconciler/v1alpha1/eventtype/eventtype.go deleted file mode 100644 index c6fc6586dcc..00000000000 --- a/pkg/reconciler/v1alpha1/eventtype/eventtype.go +++ /dev/null @@ -1,243 +0,0 @@ -/* -Copyright 2019 The Knative Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT 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 eventtype - -import ( - "context" - "fmt" - - "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" - "github.com/knative/eventing/pkg/logging" - "go.uber.org/zap" - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/equality" - "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/dynamic" - "k8s.io/client-go/rest" - "k8s.io/client-go/tools/record" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller" - "sigs.k8s.io/controller-runtime/pkg/handler" - "sigs.k8s.io/controller-runtime/pkg/manager" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - "sigs.k8s.io/controller-runtime/pkg/source" -) - -const ( - // controllerAgentName is the string used by this controller to identify - // itself when creating events. - controllerAgentName = "eventtype-controller" - - // Name of the corev1.Events emitted from the reconciliation process. - eventTypeReconciled = "EventTypeReconciled" - eventTypeReconcileFailed = "EventTypeReconcileFailed" - eventTypeUpdateStatusFailed = "EventTypeUpdateStatusFailed" -) - -type reconciler struct { - client client.Client - dynamicClient dynamic.Interface - recorder record.EventRecorder - - logger *zap.Logger -} - -// Verify the struct implements reconcile.Reconciler. -var _ reconcile.Reconciler = &reconciler{} - -// ProvideController returns a function that returns an EventType controller. -func ProvideController(mgr manager.Manager, logger *zap.Logger) (controller.Controller, error) { - // Setup a new controller to Reconcile EventTypes. - r := &reconciler{ - recorder: mgr.GetRecorder(controllerAgentName), - logger: logger, - } - c, err := controller.New(controllerAgentName, mgr, controller.Options{ - Reconciler: r, - }) - if err != nil { - return nil, err - } - - // Watch EventTypes. - if err = c.Watch(&source.Kind{Type: &v1alpha1.EventType{}}, &handler.EnqueueRequestForObject{}); err != nil { - return nil, err - } - - // Watch for Broker changes. E.g. if the Broker is deleted, we need to reconcile its EventTypes again. - if err = c.Watch(&source.Kind{Type: &v1alpha1.Broker{}}, &handler.EnqueueRequestsFromMapFunc{ToRequests: &mapBrokerToEventTypes{r: r}}); err != nil { - return nil, err - } - - return c, nil -} - -// mapBrokerToEventTypes maps Broker changes to all the EventTypes that correspond to that Broker. -type mapBrokerToEventTypes struct { - r *reconciler -} - -func (b *mapBrokerToEventTypes) Map(o handler.MapObject) []reconcile.Request { - ctx := context.Background() - eventTypes := make([]reconcile.Request, 0) - - opts := &client.ListOptions{ - Namespace: o.Meta.GetNamespace(), - // Set Raw because if we need to get more than one page, then we will put the continue token - // into opts.Raw.Continue. - Raw: &metav1.ListOptions{}, - } - for { - etl := &v1alpha1.EventTypeList{} - if err := b.r.client.List(ctx, opts, etl); err != nil { - b.r.logger.Error("Error listing EventTypes when Broker changed. Some EventTypes may not be reconciled.", zap.Error(err), zap.Any("broker", o)) - return eventTypes - } - - for _, et := range etl.Items { - if et.Spec.Broker == o.Meta.GetName() { - eventTypes = append(eventTypes, reconcile.Request{ - NamespacedName: types.NamespacedName{ - Namespace: et.Namespace, - Name: et.Name, - }, - }) - } - } - if etl.Continue != "" { - opts.Raw.Continue = etl.Continue - } else { - return eventTypes - } - } -} - -func (r *reconciler) InjectClient(c client.Client) error { - r.client = c - return nil -} - -func (r *reconciler) InjectConfig(c *rest.Config) error { - var err error - r.dynamicClient, err = dynamic.NewForConfig(c) - return err -} - -// Reconcile compares the actual state with the desired, and attempts to -// converge the two. It then updates the Status block of the EventType resource -// with the current status of the resource. -func (r *reconciler) Reconcile(request reconcile.Request) (reconcile.Result, error) { - ctx := context.TODO() - ctx = logging.WithLogger(ctx, r.logger.With(zap.Any("request", request))) - - eventType := &v1alpha1.EventType{} - err := r.client.Get(ctx, request.NamespacedName, eventType) - - if errors.IsNotFound(err) { - logging.FromContext(ctx).Info("Could not find EventType") - return reconcile.Result{}, nil - } - - if err != nil { - logging.FromContext(ctx).Error("Could not get EventType", zap.Error(err)) - return reconcile.Result{}, err - } - - // Reconcile this copy of the EventType and then write back any status updates regardless of - // whether the reconcile error out. - reconcileErr := r.reconcile(ctx, eventType) - if reconcileErr != nil { - logging.FromContext(ctx).Error("Error reconciling EventType", zap.Error(reconcileErr)) - r.recorder.Eventf(eventType, corev1.EventTypeWarning, eventTypeReconcileFailed, "EventType reconciliation failed: %v", reconcileErr) - } else { - logging.FromContext(ctx).Debug("EventType reconciled") - r.recorder.Event(eventType, corev1.EventTypeNormal, eventTypeReconciled, "EventType reconciled") - } - - if _, err = r.updateStatus(eventType); err != nil { - logging.FromContext(ctx).Error("Failed to update EventType status", zap.Error(err)) - r.recorder.Eventf(eventType, corev1.EventTypeWarning, eventTypeUpdateStatusFailed, "Failed to update EventType's status: %v", err) - return reconcile.Result{}, err - } - - // Requeue if the resource is not ready - return reconcile.Result{}, reconcileErr -} - -func (r *reconciler) reconcile(ctx context.Context, et *v1alpha1.EventType) error { - et.Status.InitializeConditions() - - // 1. Verify the Broker exists. - // 2. Verify the Broker is ready. - - if et.DeletionTimestamp != nil { - // Everything is cleaned up by the garbage collector. - return nil - } - - b, err := r.getBroker(ctx, et) - if err != nil { - logging.FromContext(ctx).Error("Unable to get the Broker", zap.Error(err)) - et.Status.MarkBrokerDoesNotExist() - return err - } - et.Status.MarkBrokerExists() - - if !b.Status.IsReady() { - logging.FromContext(ctx).Error("Broker is not ready", zap.String("broker", b.Name)) - et.Status.MarkBrokerNotReady() - return fmt.Errorf("broker %q not ready", b.Name) - } - et.Status.MarkBrokerReady() - - return nil -} - -// updateStatus updates the EventType's status. -func (r *reconciler) updateStatus(eventType *v1alpha1.EventType) (*v1alpha1.EventType, error) { - ctx := context.TODO() - objectKey := client.ObjectKey{Namespace: eventType.Namespace, Name: eventType.Name} - latestEventType := &v1alpha1.EventType{} - - if err := r.client.Get(ctx, objectKey, latestEventType); err != nil { - return nil, err - } - - if equality.Semantic.DeepEqual(latestEventType.Status, eventType.Status) { - return eventType, nil - } - - latestEventType.Status = eventType.Status - if err := r.client.Status().Update(ctx, latestEventType); err != nil { - return nil, err - } - - return latestEventType, nil -} - -// getBroker returns the Broker for EventType 'et' if it exists, otherwise it returns an error. -func (r *reconciler) getBroker(ctx context.Context, et *v1alpha1.EventType) (*v1alpha1.Broker, error) { - b := &v1alpha1.Broker{} - name := types.NamespacedName{ - Namespace: et.Namespace, - Name: et.Spec.Broker, - } - err := r.client.Get(ctx, name, b) - return b, err -} From 7c9278a9369c1ee6060ccc36af613cae567186f7 Mon Sep 17 00:00:00 2001 From: nachocano Date: Thu, 25 Apr 2019 14:37:47 -0700 Subject: [PATCH 213/221] eventType controller new serving structure --- pkg/apis/eventing/v1alpha1/eventtype_types.go | 1 + pkg/reconciler/eventtype/eventtype_test.go | 368 ++++++++---------- pkg/reconciler/testing/eventtype.go | 91 +++++ pkg/reconciler/testing/listers.go | 4 + 4 files changed, 254 insertions(+), 210 deletions(-) create mode 100644 pkg/reconciler/testing/eventtype.go diff --git a/pkg/apis/eventing/v1alpha1/eventtype_types.go b/pkg/apis/eventing/v1alpha1/eventtype_types.go index 74f2f658964..51e3ac5c4fd 100644 --- a/pkg/apis/eventing/v1alpha1/eventtype_types.go +++ b/pkg/apis/eventing/v1alpha1/eventtype_types.go @@ -60,6 +60,7 @@ type EventTypeSpec struct { // Broker refers to the Broker that can provide the EventType. Broker string `json:"broker"` // Description is an optional field used to describe the EventType, in any meaningful way. + // +optional Description string `json:description,omitempty` } diff --git a/pkg/reconciler/eventtype/eventtype_test.go b/pkg/reconciler/eventtype/eventtype_test.go index 6f771867f1e..6563eeb0bd2 100644 --- a/pkg/reconciler/eventtype/eventtype_test.go +++ b/pkg/reconciler/eventtype/eventtype_test.go @@ -17,22 +17,19 @@ limitations under the License. package eventtype import ( - "context" - "errors" "fmt" "testing" "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" - controllertesting "github.com/knative/eventing/pkg/reconciler/testing" - "go.uber.org/zap" + "github.com/knative/eventing/pkg/reconciler" + . "github.com/knative/eventing/pkg/reconciler/testing" + "github.com/knative/pkg/controller" + logtesting "github.com/knative/pkg/logging/testing" + . "github.com/knative/pkg/reconciler/testing" corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" - "k8s.io/client-go/dynamic" "k8s.io/client-go/kubernetes/scheme" - "k8s.io/client-go/rest" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/client/fake" + clientgotesting "k8s.io/client-go/testing" ) const ( @@ -40,20 +37,13 @@ const ( eventTypeName = "test-eventtype" eventTypeType = "test-type" eventTypeBroker = "test-broker" + eventTypeSource = "/test-source" ) var ( trueVal = true - // deletionTime is used when objects are marked as deleted. Rfc3339Copy() - // truncates to seconds to match the loss of precision during serialization. - deletionTime = metav1.Now().Rfc3339Copy() - // Map of events to set test cases' expectations easier. - events = map[string]corev1.Event{ - eventTypeReconciled: {Reason: eventTypeReconciled, Type: corev1.EventTypeNormal}, - eventTypeReconcileFailed: {Reason: eventTypeReconcileFailed, Type: corev1.EventTypeWarning}, - eventTypeUpdateStatusFailed: {Reason: eventTypeUpdateStatusFailed, Type: corev1.EventTypeWarning}, - } + testKey = fmt.Sprintf("%s/%s", testNS, eventTypeName) ) func init() { @@ -61,219 +51,177 @@ func init() { _ = v1alpha1.AddToScheme(scheme.Scheme) } -func TestProvideController(t *testing.T) { - // TODO(grantr) This needs a mock of manager.Manager. Creating a manager - // with a fake Config fails because the Manager tries to contact the - // apiserver. - - // cfg := &rest.Config{ - // Host: "http://foo:80", - // } - // - // mgr, err := manager.New(cfg, manager.Options{}) - // if err != nil { - // t.Fatalf("Error creating manager: %v", err) - // } - // - // _, err = ProvideController(mgr) - // if err != nil { - // t.Fatalf("Error in ProvideController: %v", err) - // } -} - -func TestInjectClient(t *testing.T) { - r := &reconciler{} - orig := r.client - n := fake.NewFakeClient() - if orig == n { - t.Errorf("Original and new clients are identical: %v", orig) - } - err := r.InjectClient(n) - if err != nil { - t.Errorf("Unexpected error injecting the client: %v", err) - } - if n != r.client { - t.Errorf("Unexpected client. Expected: '%v'. Actual: '%v'", n, r.client) - } -} - -func TestInjectConfig(t *testing.T) { - r := &reconciler{} - wantCfg := &rest.Config{ - Host: "http://foo", - } - - err := r.InjectConfig(wantCfg) - if err != nil { - t.Fatalf("Unexpected error injecting the config: %v", err) - } - - wantDynClient, err := dynamic.NewForConfig(wantCfg) - if err != nil { - t.Fatalf("Unexpected error generating dynamic client: %v", err) - } - - // Since dynamicClient doesn't export any fields, we can only test its type. - switch r.dynamicClient.(type) { - case dynamic.Interface: - // ok - default: - t.Errorf("Unexpected dynamicClient type. Expected: %T, Got: %T", wantDynClient, r.dynamicClient) - } -} - func TestReconcile(t *testing.T) { - testCases := []controllertesting.TestCase{ + table := TableTest{ { - Name: "EventType not found", + Name: "bad workqueue key", + // Make sure Reconcile handles bad keys. + Key: "too/many/parts", + }, { + Name: "key not found", + // Make sure Reconcile handles good keys that don't exist. + Key: "foo/not-found", }, { - Name: "Get EventType error", - Scheme: scheme.Scheme, - Mocks: controllertesting.Mocks{ - MockGets: []controllertesting.MockGet{ - func(_ client.Client, _ context.Context, _ client.ObjectKey, obj runtime.Object) (controllertesting.MockHandled, error) { - if _, ok := obj.(*v1alpha1.EventType); ok { - return controllertesting.Handled, errors.New("test error getting the EventType") - } - return controllertesting.Unhandled, nil - }, - }, - }, - WantErrMsg: "test error getting the EventType", + Name: "EventType not found", + Key: testKey, }, { - Name: "EventType being deleted", - Scheme: scheme.Scheme, - InitialState: []runtime.Object{ - makeDeletingEventType(), + Name: "EventType being deleted", + Key: testKey, + Objects: []runtime.Object{ + NewEventType(eventTypeName, testNS, + WithInitEventTypeConditions, + WithEventTypeDeletionTimestamp), }, - WantEvent: []corev1.Event{events[eventTypeReconciled]}, }, { - Name: "Get Broker error", - Scheme: scheme.Scheme, - InitialState: []runtime.Object{ - makeEventType(), - }, - Mocks: controllertesting.Mocks{ - MockGets: []controllertesting.MockGet{ - func(_ client.Client, _ context.Context, _ client.ObjectKey, obj runtime.Object) (controllertesting.MockHandled, error) { - if _, ok := obj.(*v1alpha1.Broker); ok { - return controllertesting.Handled, errors.New("test error getting broker") - } - return controllertesting.Unhandled, nil - }, - }, + Name: "Broker not found", + Key: testKey, + Objects: []runtime.Object{ + NewEventType(eventTypeName, testNS, + WithEventTypeType(eventTypeType), + WithEventTypeSource(eventTypeSource), + WithEventTypeBroker(eventTypeBroker), + ), }, - WantErrMsg: "test error getting broker", - WantEvent: []corev1.Event{events[eventTypeReconcileFailed]}, + WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ + Object: NewEventType(eventTypeName, testNS, + WithEventTypeType(eventTypeType), + WithEventTypeSource(eventTypeSource), + WithEventTypeBroker(eventTypeBroker), + WithInitEventTypeConditions, + WithEventTypeBrokerDoesNotExist, + ), + }}, }, { - Name: "Broker not ready", - Scheme: scheme.Scheme, - InitialState: []runtime.Object{ - makeEventType(), - makeBroker(), + Name: "Broker not ready", + Key: testKey, + Objects: []runtime.Object{ + NewEventType(eventTypeName, testNS, + WithEventTypeType(eventTypeType), + WithEventTypeSource(eventTypeSource), + WithEventTypeBroker(eventTypeBroker), + ), + NewBroker(eventTypeBroker, testNS, + WithInitBrokerConditions, + ), }, - WantErrMsg: `broker "` + eventTypeBroker + `" not ready`, - WantEvent: []corev1.Event{events[eventTypeReconcileFailed]}, + WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ + Object: NewEventType(eventTypeName, testNS, + WithEventTypeType(eventTypeType), + WithEventTypeSource(eventTypeSource), + WithEventTypeBroker(eventTypeBroker), + WithEventTypeBrokerExists, + WithEventTypeBrokerNotReady, + ), + }}, }, { - Name: "EventType reconciliation success", - Scheme: scheme.Scheme, - InitialState: []runtime.Object{ - makeEventType(), - makeBrokerReady(), + Name: "Successful reconcile, became ready", + Key: testKey, + Objects: []runtime.Object{ + NewEventType(eventTypeName, testNS, + WithEventTypeType(eventTypeType), + WithEventTypeSource(eventTypeSource), + WithEventTypeBroker(eventTypeBroker), + ), + NewBroker(eventTypeBroker, testNS, + WithBrokerReady, + ), }, - WantEvent: []corev1.Event{events[eventTypeReconciled]}, - WantPresent: []runtime.Object{ - makeReadyEventType(), + WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ + Object: NewEventType(eventTypeName, testNS, + WithEventTypeType(eventTypeType), + WithEventTypeSource(eventTypeSource), + WithEventTypeBroker(eventTypeBroker), + WithEventTypeBrokerExists, + WithEventTypeBrokerReady, + ), + }}, + WantEvents: []string{ + Eventf(corev1.EventTypeNormal, eventTypeReadinessChanged, "EventType %q became ready", eventTypeName), }, }, } - for _, tc := range testCases { - c := tc.GetClient() - dc := tc.GetDynamicClient() - recorder := tc.GetEventRecorder() - r := &reconciler{ - client: c, - dynamicClient: dc, - recorder: recorder, - logger: zap.NewNop(), + defer logtesting.ClearAll() + table.Test(t, MakeFactory(func(listers *Listers, opt reconciler.Options) controller.Reconciler { + return &Reconciler{ + Base: reconciler.NewBase(opt, controllerAgentName), + eventTypeLister: listers.GetEventTypeLister(), + brokerLister: listers.GetBrokerLister(), } - tc.ReconcileKey = fmt.Sprintf("%s/%s", testNS, eventTypeName) - tc.IgnoreTimes = true - t.Run(tc.Name, tc.Runner(t, r, c, recorder)) - } -} + })) -func makeEventType() *v1alpha1.EventType { - return &v1alpha1.EventType{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "eventing.knative.dev/v1alpha1", - Kind: "EventType", - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: testNS, - Name: eventTypeName, - }, - Spec: v1alpha1.EventTypeSpec{ - Broker: eventTypeBroker, - Type: eventTypeType, - }, - } } -func makeReadyEventType() *v1alpha1.EventType { - t := makeEventType() - t.Status.InitializeConditions() - t.Status.MarkBrokerExists() - t.Status.MarkBrokerReady() - return t -} - -func makeDeletingEventType() *v1alpha1.EventType { - et := makeReadyEventType() - et.DeletionTimestamp = &deletionTime - return et -} - -func makeBroker() *v1alpha1.Broker { - return &v1alpha1.Broker{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "eventing.knative.dev/v1alpha1", - Kind: "Broker", - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: testNS, - Name: eventTypeBroker, - }, - Spec: v1alpha1.BrokerSpec{ - ChannelTemplate: &v1alpha1.ChannelSpec{ - Provisioner: makeChannelProvisioner(), - }, - }, - } -} - -func makeBrokerReady() *v1alpha1.Broker { - b := makeBroker() - b.Status.InitializeConditions() - b.Status.MarkTriggerChannelReady() - b.Status.MarkFilterReady() - b.Status.MarkIngressReady() - b.Status.SetAddress("test-address") - b.Status.MarkIngressChannelReady() - b.Status.MarkIngressSubscriptionReady() - return b -} - -func makeChannelProvisioner() *corev1.ObjectReference { - return &corev1.ObjectReference{ - APIVersion: "eventing.knative.dev/v1alpha1", - Kind: "ClusterChannelProvisioner", - Name: "my-provisioner", - } -} +//func makeEventType() *v1alpha1.EventType { +// return &v1alpha1.EventType{ +// TypeMeta: metav1.TypeMeta{ +// APIVersion: "eventing.knative.dev/v1alpha1", +// Kind: "EventType", +// }, +// ObjectMeta: metav1.ObjectMeta{ +// Namespace: testNS, +// Name: eventTypeName, +// }, +// Spec: v1alpha1.EventTypeSpec{ +// Broker: eventTypeBroker, +// Type: eventTypeType, +// }, +// } +//} + +//func makeReadyEventType() *v1alpha1.EventType { +// t := makeEventType() +// t.Status.InitializeConditions() +// t.Status.MarkBrokerExists() +// t.Status.MarkBrokerReady() +// return t +//} +// +//func makeDeletingEventType() *v1alpha1.EventType { +// et := makeReadyEventType() +// et.DeletionTimestamp = &deletionTime +// return et +//} +// +//func makeBroker() *v1alpha1.Broker { +// return &v1alpha1.Broker{ +// TypeMeta: metav1.TypeMeta{ +// APIVersion: "eventing.knative.dev/v1alpha1", +// Kind: "Broker", +// }, +// ObjectMeta: metav1.ObjectMeta{ +// Namespace: testNS, +// Name: eventTypeBroker, +// }, +// Spec: v1alpha1.BrokerSpec{ +// ChannelTemplate: &v1alpha1.ChannelSpec{ +// Provisioner: makeChannelProvisioner(), +// }, +// }, +// } +//} +// +//func makeBrokerReady() *v1alpha1.Broker { +// b := makeBroker() +// b.Status.InitializeConditions() +// b.Status.MarkTriggerChannelReady() +// b.Status.MarkFilterReady() +// b.Status.MarkIngressReady() +// b.Status.SetAddress("test-address") +// b.Status.MarkIngressChannelReady() +// b.Status.MarkIngressSubscriptionReady() +// return b +//} +// +//func makeChannelProvisioner() *corev1.ObjectReference { +// return &corev1.ObjectReference{ +// APIVersion: "eventing.knative.dev/v1alpha1", +// Kind: "ClusterChannelProvisioner", +// Name: "my-provisioner", +// } +//} diff --git a/pkg/reconciler/testing/eventtype.go b/pkg/reconciler/testing/eventtype.go new file mode 100644 index 00000000000..828659684f6 --- /dev/null +++ b/pkg/reconciler/testing/eventtype.go @@ -0,0 +1,91 @@ +/* +Copyright 2019 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT 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 testing + +import ( + "context" + "time" + + "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// EventTypeOption enables further configuration of an EventType. +type EventTypeOption func(*v1alpha1.EventType) + +// NewEventType creates a EventType with EventTypeOptions. +func NewEventType(name, namespace string, o ...EventTypeOption) *v1alpha1.EventType { + et := &v1alpha1.EventType{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: namespace, + Name: name, + }, + } + for _, opt := range o { + opt(et) + } + et.SetDefaults(context.Background()) + return et +} + +// WithInitEventTypeConditions initializes the EventType's conditions. +func WithInitEventTypeConditions(et *v1alpha1.EventType) { + et.Status.InitializeConditions() +} + +func WithEventTypeSource(source string) EventTypeOption { + return func(et *v1alpha1.EventType) { + et.Spec.Source = source + } +} + +func WithEventTypeType(t string) EventTypeOption { + return func(et *v1alpha1.EventType) { + et.Spec.Type = t + } +} + +func WithEventTypeBroker(broker string) EventTypeOption { + return func(et *v1alpha1.EventType) { + et.Spec.Broker = broker + } +} + +func WithEventTypeDeletionTimestamp(et *v1alpha1.EventType) { + t := metav1.NewTime(time.Unix(1e9, 0)) + et.ObjectMeta.SetDeletionTimestamp(&t) +} + +// WithEventTypeBrokerNotFound calls .Status.MarkFilterFailed on the EventType. +func WithEventTypeBrokerDoesNotExist(et *v1alpha1.EventType) { + et.Status.MarkBrokerDoesNotExist() +} + +// WithEventTypeBrokerExists calls .Status.MarkBrokerExists on the EventType. +func WithEventTypeBrokerExists(et *v1alpha1.EventType) { + et.Status.MarkBrokerExists() +} + +// WithEventTypeBrokerNotReady calls .Status.MarkBrokerNotReady on the EventType. +func WithEventTypeBrokerNotReady(et *v1alpha1.EventType) { + et.Status.MarkBrokerNotReady() +} + +// WithEventTypeBrokerReady calls .Status.MarkBrokerReady on the EventType. +func WithEventTypeBrokerReady(et *v1alpha1.EventType) { + et.Status.MarkBrokerReady() +} diff --git a/pkg/reconciler/testing/listers.go b/pkg/reconciler/testing/listers.go index 8d634d3a91c..da772481d70 100644 --- a/pkg/reconciler/testing/listers.go +++ b/pkg/reconciler/testing/listers.go @@ -108,6 +108,10 @@ func (l *Listers) GetBrokerLister() eventinglisters.BrokerLister { return eventinglisters.NewBrokerLister(l.indexerFor(&eventingv1alpha1.Broker{})) } +func (l *Listers) GetEventTypeLister() eventinglisters.EventTypeLister { + return eventinglisters.NewEventTypeLister(l.indexerFor(&eventingv1alpha1.EventType{})) +} + func (l *Listers) GetChannelLister() eventinglisters.ChannelLister { return eventinglisters.NewChannelLister(l.indexerFor(&eventingv1alpha1.Channel{})) } From 02f482490f475600fa12123821bf88c522c7956b Mon Sep 17 00:00:00 2001 From: nachocano Date: Thu, 25 Apr 2019 14:48:35 -0700 Subject: [PATCH 214/221] bug --- pkg/reconciler/eventtype/eventtype.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pkg/reconciler/eventtype/eventtype.go b/pkg/reconciler/eventtype/eventtype.go index 173c01529fd..98a8d70ef98 100644 --- a/pkg/reconciler/eventtype/eventtype.go +++ b/pkg/reconciler/eventtype/eventtype.go @@ -70,8 +70,9 @@ func NewController( ) *controller.Impl { r := &Reconciler{ - Base: reconciler.NewBase(opt, controllerAgentName), - brokerLister: brokerInformer.Lister(), + Base: reconciler.NewBase(opt, controllerAgentName), + eventTypeLister: eventTypeInformer.Lister(), + brokerLister: brokerInformer.Lister(), } impl := controller.NewImpl(r, r.Logger, ReconcilerName, reconciler.MustNewStatsReporter(ReconcilerName, r.Logger)) From 28c5771cdf092e67ea319acfa7d23a0d34238244 Mon Sep 17 00:00:00 2001 From: nachocano Date: Thu, 25 Apr 2019 14:56:22 -0700 Subject: [PATCH 215/221] removing commented code --- pkg/reconciler/eventtype/eventtype_test.go | 69 ---------------------- 1 file changed, 69 deletions(-) diff --git a/pkg/reconciler/eventtype/eventtype_test.go b/pkg/reconciler/eventtype/eventtype_test.go index 6563eeb0bd2..6b2725ed67a 100644 --- a/pkg/reconciler/eventtype/eventtype_test.go +++ b/pkg/reconciler/eventtype/eventtype_test.go @@ -156,72 +156,3 @@ func TestReconcile(t *testing.T) { })) } - -//func makeEventType() *v1alpha1.EventType { -// return &v1alpha1.EventType{ -// TypeMeta: metav1.TypeMeta{ -// APIVersion: "eventing.knative.dev/v1alpha1", -// Kind: "EventType", -// }, -// ObjectMeta: metav1.ObjectMeta{ -// Namespace: testNS, -// Name: eventTypeName, -// }, -// Spec: v1alpha1.EventTypeSpec{ -// Broker: eventTypeBroker, -// Type: eventTypeType, -// }, -// } -//} - -//func makeReadyEventType() *v1alpha1.EventType { -// t := makeEventType() -// t.Status.InitializeConditions() -// t.Status.MarkBrokerExists() -// t.Status.MarkBrokerReady() -// return t -//} -// -//func makeDeletingEventType() *v1alpha1.EventType { -// et := makeReadyEventType() -// et.DeletionTimestamp = &deletionTime -// return et -//} -// -//func makeBroker() *v1alpha1.Broker { -// return &v1alpha1.Broker{ -// TypeMeta: metav1.TypeMeta{ -// APIVersion: "eventing.knative.dev/v1alpha1", -// Kind: "Broker", -// }, -// ObjectMeta: metav1.ObjectMeta{ -// Namespace: testNS, -// Name: eventTypeBroker, -// }, -// Spec: v1alpha1.BrokerSpec{ -// ChannelTemplate: &v1alpha1.ChannelSpec{ -// Provisioner: makeChannelProvisioner(), -// }, -// }, -// } -//} -// -//func makeBrokerReady() *v1alpha1.Broker { -// b := makeBroker() -// b.Status.InitializeConditions() -// b.Status.MarkTriggerChannelReady() -// b.Status.MarkFilterReady() -// b.Status.MarkIngressReady() -// b.Status.SetAddress("test-address") -// b.Status.MarkIngressChannelReady() -// b.Status.MarkIngressSubscriptionReady() -// return b -//} -// -//func makeChannelProvisioner() *corev1.ObjectReference { -// return &corev1.ObjectReference{ -// APIVersion: "eventing.knative.dev/v1alpha1", -// Kind: "ClusterChannelProvisioner", -// Name: "my-provisioner", -// } -//} From d0151aa4cf13a68422b79fe7dda2e899ed8223c8 Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Thu, 25 Apr 2019 15:10:50 -0700 Subject: [PATCH 216/221] adding Gopkg.lock --- Gopkg.lock | 1 - 1 file changed, 1 deletion(-) diff --git a/Gopkg.lock b/Gopkg.lock index 4a9d72ffbee..0fd66fadcbc 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -1432,7 +1432,6 @@ "k8s.io/apimachinery/pkg/util/sets", "k8s.io/apimachinery/pkg/util/sets/types", "k8s.io/apimachinery/pkg/util/uuid", - "k8s.io/apimachinery/pkg/util/validation", "k8s.io/apimachinery/pkg/util/wait", "k8s.io/apimachinery/pkg/util/yaml", "k8s.io/apimachinery/pkg/watch", From fb8bd9fa5ce0a614d02c3375f9b102df23ac408c Mon Sep 17 00:00:00 2001 From: nachocano Date: Thu, 25 Apr 2019 16:38:49 -0700 Subject: [PATCH 217/221] rollback source getter --- docs/registry/example_eventtype.yaml | 8 ++++---- pkg/broker/receiver.go | 3 ++- pkg/reconciler/eventtype/eventtype.go | 6 ++---- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/docs/registry/example_eventtype.yaml b/docs/registry/example_eventtype.yaml index bac0223ad35..17b12a44545 100644 --- a/docs/registry/example_eventtype.yaml +++ b/docs/registry/example_eventtype.yaml @@ -15,7 +15,7 @@ --- # This EventType creates an event type with type 'com.github.pull_request', source -# 'github.com', for the 'broker-allow-registered' Broker. +# 'github.com', for the 'default' Broker. apiVersion: eventing.knative.dev/v1alpha1 kind: EventType @@ -24,13 +24,13 @@ metadata: spec: type: com.github.pull_request source: github.com - broker: broker-allow-registered + broker: default description: "GitHub Pull Request" --- # This Trigger matches all events of type 'com.github.pull_request' and source -# 'github.com', that are sent to the 'broker-allow-registered' Broker. +# 'github.com', that are sent to the 'default' Broker. apiVersion: eventing.knative.dev/v1alpha1 kind: Trigger @@ -41,7 +41,7 @@ spec: sourceAndType: type: com.github.pull_request source: github.com - broker: broker-allow-registered + broker: default subscriber: ref: apiVersion: serving.knative.dev/v1alpha1 diff --git a/pkg/broker/receiver.go b/pkg/broker/receiver.go index 86b5c4381ef..4904c7c3b23 100644 --- a/pkg/broker/receiver.go +++ b/pkg/broker/receiver.go @@ -214,7 +214,8 @@ func (r *Receiver) shouldSendMessage(ts *eventingv1alpha1.TriggerSpec, event *cl return false } filterSource := ts.Filter.SourceAndType.Source - actualSource := event.Source() + s := event.Context.AsV01().Source + actualSource := s.String() if filterSource != eventingv1alpha1.TriggerAnyFilter && filterSource != actualSource { r.logger.Debug("Wrong source", zap.String("trigger.spec.filter.sourceAndType.source", filterSource), zap.String("message.source", actualSource)) return false diff --git a/pkg/reconciler/eventtype/eventtype.go b/pkg/reconciler/eventtype/eventtype.go index 98a8d70ef98..20ac919d340 100644 --- a/pkg/reconciler/eventtype/eventtype.go +++ b/pkg/reconciler/eventtype/eventtype.go @@ -24,14 +24,12 @@ import ( "k8s.io/client-go/tools/cache" - "github.com/knative/pkg/controller" - - "github.com/knative/eventing/pkg/reconciler" - "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" eventinginformers "github.com/knative/eventing/pkg/client/informers/externalversions/eventing/v1alpha1" listers "github.com/knative/eventing/pkg/client/listers/eventing/v1alpha1" "github.com/knative/eventing/pkg/logging" + "github.com/knative/eventing/pkg/reconciler" + "github.com/knative/pkg/controller" "go.uber.org/zap" corev1 "k8s.io/api/core/v1" apierrs "k8s.io/apimachinery/pkg/api/errors" From 394ad770fe0105579dd830a7762a5a8b6575d910 Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Thu, 25 Apr 2019 22:26:13 -0700 Subject: [PATCH 218/221] permissions!!! damn... --- config/200-controller-clusterrole.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/config/200-controller-clusterrole.yaml b/config/200-controller-clusterrole.yaml index 5be03648e78..60afacc783d 100644 --- a/config/200-controller-clusterrole.yaml +++ b/config/200-controller-clusterrole.yaml @@ -70,6 +70,8 @@ rules: - "subscriptions/status" - "triggers" - "triggers/status" + - "eventtypes" + - "eventtypes/status" verbs: *everything # Source resources and statuses we care about. From 104849ba5a816dfa0a0a2b31c06b4b51164b972d Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Thu, 25 Apr 2019 22:28:40 -0700 Subject: [PATCH 219/221] permissions. --- config/200-webhook-clusterrole.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/config/200-webhook-clusterrole.yaml b/config/200-webhook-clusterrole.yaml index 89823ca6cb1..53176c1013a 100644 --- a/config/200-webhook-clusterrole.yaml +++ b/config/200-webhook-clusterrole.yaml @@ -79,6 +79,8 @@ rules: - "subscriptions/status" - "triggers" - "triggers/status" + - "eventtypes" + - "eventtypes/status" verbs: - "get" - "list" From a7fe9f217cff847d9998b2afda64838abfcb0863 Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Thu, 25 Apr 2019 22:33:27 -0700 Subject: [PATCH 220/221] removing formatting of imports in goland --- cmd/broker/ingress/main.go | 2 +- pkg/broker/context.go | 2 +- pkg/broker/receiver.go | 2 +- pkg/broker/receiver_test.go | 2 +- pkg/broker/ttl.go | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cmd/broker/ingress/main.go b/cmd/broker/ingress/main.go index c406b9e406b..672516b69f4 100644 --- a/cmd/broker/ingress/main.go +++ b/cmd/broker/ingress/main.go @@ -29,7 +29,7 @@ import ( "sync" "time" - cloudevents "github.com/cloudevents/sdk-go" + "github.com/cloudevents/sdk-go" eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" "github.com/knative/eventing/pkg/broker" "github.com/knative/eventing/pkg/provisioners" diff --git a/pkg/broker/context.go b/pkg/broker/context.go index fd336f5123e..a06be9244d4 100644 --- a/pkg/broker/context.go +++ b/pkg/broker/context.go @@ -22,7 +22,7 @@ import ( "net/url" "strings" - cloudevents "github.com/cloudevents/sdk-go" + "github.com/cloudevents/sdk-go" "k8s.io/apimachinery/pkg/util/sets" ) diff --git a/pkg/broker/receiver.go b/pkg/broker/receiver.go index 4904c7c3b23..675af6a3ca9 100644 --- a/pkg/broker/receiver.go +++ b/pkg/broker/receiver.go @@ -23,7 +23,7 @@ import ( "net/url" "time" - cloudevents "github.com/cloudevents/sdk-go" + "github.com/cloudevents/sdk-go" eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" "github.com/knative/eventing/pkg/reconciler/trigger/path" "go.uber.org/zap" diff --git a/pkg/broker/receiver_test.go b/pkg/broker/receiver_test.go index e299178f969..ed14a6c0041 100644 --- a/pkg/broker/receiver_test.go +++ b/pkg/broker/receiver_test.go @@ -26,7 +26,7 @@ import ( "strings" "testing" - cloudevents "github.com/cloudevents/sdk-go" + "github.com/cloudevents/sdk-go" cehttp "github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http" "github.com/google/go-cmp/cmp" eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" diff --git a/pkg/broker/ttl.go b/pkg/broker/ttl.go index d71f425b8a7..8d7ccdef39f 100644 --- a/pkg/broker/ttl.go +++ b/pkg/broker/ttl.go @@ -17,7 +17,7 @@ package broker import ( - cloudevents "github.com/cloudevents/sdk-go" + "github.com/cloudevents/sdk-go" ) const ( From 4772ab82bd7ee545099b8d22dd478bd59fefab9e Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Fri, 26 Apr 2019 09:04:57 -0700 Subject: [PATCH 221/221] tracking changes to broker as trigger does. --- pkg/reconciler/eventtype/eventtype.go | 24 ++++++++++++++++++++-- pkg/reconciler/eventtype/eventtype_test.go | 7 +++++++ pkg/reconciler/trigger/trigger.go | 24 +++------------------- pkg/utils/utils.go | 17 +++++++++++++++ 4 files changed, 49 insertions(+), 23 deletions(-) diff --git a/pkg/reconciler/eventtype/eventtype.go b/pkg/reconciler/eventtype/eventtype.go index 20ac919d340..a1aa28113a8 100644 --- a/pkg/reconciler/eventtype/eventtype.go +++ b/pkg/reconciler/eventtype/eventtype.go @@ -22,6 +22,9 @@ import ( "reflect" "time" + "github.com/knative/eventing/pkg/utils" + "github.com/knative/pkg/tracker" + "k8s.io/client-go/tools/cache" "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" @@ -54,8 +57,11 @@ type Reconciler struct { // listers index properties about resources eventTypeLister listers.EventTypeLister brokerLister listers.BrokerLister + tracker tracker.Interface } +var brokerGVK = v1alpha1.SchemeGroupVersion.WithKind("Broker") + // Check that our Reconciler implements controller.Reconciler var _ controller.Reconciler = (*Reconciler)(nil) @@ -77,7 +83,15 @@ func NewController( r.Logger.Info("Setting up event handlers") eventTypeInformer.Informer().AddEventHandler(reconciler.Handler(impl.Enqueue)) - // TODO Watch for Broker changes. E.g. if the Broker is deleted, we need to reconcile its EventTypes again. + // Tracker is used to notify us that a EventType's Broker has changed so that + // we can reconcile. + r.tracker = tracker.New(impl.EnqueueKey, opt.GetTrackerLease()) + brokerInformer.Informer().AddEventHandler(reconciler.Handler( + controller.EnsureTypeMeta( + r.tracker.OnChanged, + v1alpha1.SchemeGroupVersion.WithKind("Broker"), + ), + )) return impl } @@ -142,10 +156,16 @@ func (r *Reconciler) reconcile(ctx context.Context, et *v1alpha1.EventType) erro if err != nil { logging.FromContext(ctx).Error("Unable to get the Broker", zap.Error(err)) et.Status.MarkBrokerDoesNotExist() - return nil + return err } et.Status.MarkBrokerExists() + // Tell tracker to reconcile this EventType whenever the Broker changes. + if err = r.tracker.Track(utils.ObjectRef(b, brokerGVK), et); err != nil { + logging.FromContext(ctx).Error("Unable to track changes to Broker", zap.Error(err)) + return err + } + if !b.Status.IsReady() { logging.FromContext(ctx).Error("Broker is not ready", zap.String("broker", b.Name)) et.Status.MarkBrokerNotReady() diff --git a/pkg/reconciler/eventtype/eventtype_test.go b/pkg/reconciler/eventtype/eventtype_test.go index 6b2725ed67a..1ea039e539f 100644 --- a/pkg/reconciler/eventtype/eventtype_test.go +++ b/pkg/reconciler/eventtype/eventtype_test.go @@ -20,6 +20,8 @@ import ( "fmt" "testing" + "github.com/knative/pkg/tracker" + "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" "github.com/knative/eventing/pkg/reconciler" . "github.com/knative/eventing/pkg/reconciler/testing" @@ -94,6 +96,10 @@ func TestReconcile(t *testing.T) { WithEventTypeBrokerDoesNotExist, ), }}, + WantErr: true, + WantEvents: []string{ + Eventf(corev1.EventTypeWarning, eventTypeReconcileFailed, "EventType reconcile error: broker.eventing.knative.dev %q not found", eventTypeBroker), + }, }, { Name: "Broker not ready", @@ -152,6 +158,7 @@ func TestReconcile(t *testing.T) { Base: reconciler.NewBase(opt, controllerAgentName), eventTypeLister: listers.GetEventTypeLister(), brokerLister: listers.GetBrokerLister(), + tracker: tracker.New(func(string) {}, 0), } })) diff --git a/pkg/reconciler/trigger/trigger.go b/pkg/reconciler/trigger/trigger.go index 473ce7c8e4f..d046ce10a9f 100644 --- a/pkg/reconciler/trigger/trigger.go +++ b/pkg/reconciler/trigger/trigger.go @@ -23,6 +23,8 @@ import ( "reflect" "time" + "github.com/knative/eventing/pkg/utils" + "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" eventinginformers "github.com/knative/eventing/pkg/client/informers/externalversions/eventing/v1alpha1" listers "github.com/knative/eventing/pkg/client/listers/eventing/v1alpha1" @@ -206,7 +208,7 @@ func (r *Reconciler) reconcile(ctx context.Context, t *v1alpha1.Trigger) error { t.Status.PropagateBrokerStatus(&b.Status) // Tell tracker to reconcile this Trigger whenever the Broker changes. - if err = r.tracker.Track(objectRef(b, brokerGVK), t); err != nil { + if err = r.tracker.Track(utils.ObjectRef(b, brokerGVK), t); err != nil { logging.FromContext(ctx).Error("Unable to track changes to Broker", zap.Error(err)) return err } @@ -406,23 +408,3 @@ func (r *Reconciler) getSubscription(ctx context.Context, t *v1alpha1.Trigger) ( return nil, apierrs.NewNotFound(schema.GroupResource{}, "") } - -type accessor interface { - GroupVersionKind() schema.GroupVersionKind - GetNamespace() string - GetName() string -} - -func objectRef(a accessor, gvk schema.GroupVersionKind) corev1.ObjectReference { - // We can't always rely on the TypeMeta being populated. - // See: https://github.com/knative/serving/issues/2372 - // Also: https://github.com/kubernetes/apiextensions-apiserver/issues/29 - // gvk := a.GroupVersionKind() - apiVersion, kind := gvk.ToAPIVersionAndKind() - return corev1.ObjectReference{ - APIVersion: apiVersion, - Kind: kind, - Namespace: a.GetNamespace(), - Name: a.GetName(), - } -} diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index 33482fc0523..1f9bc2ec1e8 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -22,6 +22,10 @@ import ( "os" "strings" "sync" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" ) const ( @@ -67,3 +71,16 @@ func getClusterDomainName(r io.Reader) string { // For all abnormal cases return default domain name return defaultDomainName } + +func ObjectRef(obj metav1.Object, gvk schema.GroupVersionKind) corev1.ObjectReference { + // We can't always rely on the TypeMeta being populated. + // See: https://github.com/knative/serving/issues/2372 + // Also: https://github.com/kubernetes/apiextensions-apiserver/issues/29 + apiVersion, kind := gvk.ToAPIVersionAndKind() + return corev1.ObjectReference{ + APIVersion: apiVersion, + Kind: kind, + Namespace: obj.GetNamespace(), + Name: obj.GetName(), + } +}