diff --git a/cmd/webhook/main.go b/cmd/webhook/main.go index aefd15caff0..8388bb45502 100644 --- a/cmd/webhook/main.go +++ b/cmd/webhook/main.go @@ -92,6 +92,7 @@ func main() { // For group eventing.knative.dev, eventingv1alpha1.SchemeGroupVersion.WithKind("Channel"): &eventingv1alpha1.Channel{}, eventingv1alpha1.SchemeGroupVersion.WithKind("ClusterProvisioner"): &eventingv1alpha1.ClusterProvisioner{}, + eventingv1alpha1.SchemeGroupVersion.WithKind("Source"): &eventingv1alpha1.Source{}, eventingv1alpha1.SchemeGroupVersion.WithKind("Subscription"): &eventingv1alpha1.Subscription{}, // For group channels.knative.dev, diff --git a/config/300-source.yaml b/config/300-source.yaml new file mode 100644 index 00000000000..82942812712 --- /dev/null +++ b/config/300-source.yaml @@ -0,0 +1,29 @@ +# 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: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: sources.eventing.knative.dev +spec: + group: eventing.knative.dev + version: v1alpha1 + names: + kind: Sources + plural: sources + singular: source + categories: + - all + - knative + - eventing + scope: Namespaced diff --git a/pkg/apis/eventing/v1alpha1/channel_validation_test.go b/pkg/apis/eventing/v1alpha1/channel_validation_test.go index cc684046ea8..817656e489f 100644 --- a/pkg/apis/eventing/v1alpha1/channel_validation_test.go +++ b/pkg/apis/eventing/v1alpha1/channel_validation_test.go @@ -29,13 +29,9 @@ import ( var targetURI = "https://example.com" func TestChannelValidation(t *testing.T) { - tests := []struct { - name string - c *Channel - want *apis.FieldError - }{{ + tests := []CRDTest{{ name: "valid", - c: &Channel{ + cr: &Channel{ Spec: ChannelSpec{ Provisioner: &ProvisionerReference{ Ref: &corev1.ObjectReference{ @@ -47,13 +43,13 @@ func TestChannelValidation(t *testing.T) { want: nil, }, { name: "empty", - c: &Channel{ + cr: &Channel{ Spec: ChannelSpec{}, }, want: apis.ErrMissingField("spec.provisioner"), }, { name: "subscribers array", - c: &Channel{ + cr: &Channel{ Spec: ChannelSpec{ Provisioner: &ProvisionerReference{ Ref: &corev1.ObjectReference{ @@ -70,7 +66,7 @@ func TestChannelValidation(t *testing.T) { want: nil, }, { name: "empty subscriber at index 1", - c: &Channel{ + cr: &Channel{ Spec: ChannelSpec{ Provisioner: &ProvisionerReference{ Ref: &corev1.ObjectReference{ @@ -91,7 +87,7 @@ func TestChannelValidation(t *testing.T) { }(), }, { name: "2 empty subscribers", - c: &Channel{ + cr: &Channel{ Spec: ChannelSpec{ Provisioner: &ProvisionerReference{ Ref: &corev1.ObjectReference{ @@ -115,14 +111,7 @@ func TestChannelValidation(t *testing.T) { }(), }} - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - got := test.c.Validate() - if diff := cmp.Diff(test.want.Error(), got.Error()); diff != "" { - t.Errorf("validateChannel (-want, +got) = %v", diff) - } - }) - } + doValidateTest(t, tests) } func TestChannelImmutableFields(t *testing.T) { diff --git a/pkg/apis/eventing/v1alpha1/cluster_provisioner_types.go b/pkg/apis/eventing/v1alpha1/cluster_provisioner_types.go index 7d0b78930fa..3be26f37d00 100644 --- a/pkg/apis/eventing/v1alpha1/cluster_provisioner_types.go +++ b/pkg/apis/eventing/v1alpha1/cluster_provisioner_types.go @@ -79,6 +79,9 @@ var cProvCondSet = duckv1alpha1.NewLivingConditionSet() // ClusterProvisionerStatus is the status for a ClusterProvisioner resource type ClusterProvisionerStatus struct { // Conditions holds the state of a cluster provisioner at a point in time. + // +optional + // +patchMergeKey=type + // +patchStrategy=merge Conditions duckv1alpha1.Conditions `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"` // ObservedGeneration is the 'Generation' of the ClusterProvisioner that diff --git a/pkg/apis/eventing/v1alpha1/cluster_provisioner_validation_test.go b/pkg/apis/eventing/v1alpha1/cluster_provisioner_validation_test.go index 9629ca91f34..7d77e4a6d8c 100644 --- a/pkg/apis/eventing/v1alpha1/cluster_provisioner_validation_test.go +++ b/pkg/apis/eventing/v1alpha1/cluster_provisioner_validation_test.go @@ -23,7 +23,7 @@ import ( "testing" ) -func TestValidate(t *testing.T) { +func TestClusterProvisionerValidate(t *testing.T) { tests := []struct { name string p *ClusterProvisioner diff --git a/pkg/apis/eventing/v1alpha1/crd_validation_test.go b/pkg/apis/eventing/v1alpha1/crd_validation_test.go new file mode 100644 index 00000000000..f052c52b9fa --- /dev/null +++ b/pkg/apis/eventing/v1alpha1/crd_validation_test.go @@ -0,0 +1,41 @@ +/* +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" + "github.com/knative/pkg/webhook" + "testing" +) + +type CRDTest struct { + name string + cr webhook.GenericCRD + want *apis.FieldError +} + +func doValidateTest(t *testing.T, tests []CRDTest) { + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := test.cr.Validate() + if diff := cmp.Diff(test.want.Error(), got.Error()); diff != "" { + t.Errorf("%s: validate (-want, +got) = %v", test.name, diff) + } + }) + } +} diff --git a/pkg/apis/eventing/v1alpha1/source_defaults.go b/pkg/apis/eventing/v1alpha1/source_defaults.go new file mode 100644 index 00000000000..9d417f8e35a --- /dev/null +++ b/pkg/apis/eventing/v1alpha1/source_defaults.go @@ -0,0 +1,27 @@ +/* +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 + +// SetDefaults defaults +func (s *Source) SetDefaults() { + s.Spec.SetDefaults() +} + +// SetDefaults defaults the Source spec. +func (ss *SourceSpec) SetDefaults() { + // no defaults +} diff --git a/pkg/apis/eventing/v1alpha1/source_defaults_test.go b/pkg/apis/eventing/v1alpha1/source_defaults_test.go new file mode 100644 index 00000000000..2373f9a70c8 --- /dev/null +++ b/pkg/apis/eventing/v1alpha1/source_defaults_test.go @@ -0,0 +1,27 @@ +/* +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" +) + +// No-op test because method does nothing. +func TestSourceSetDefaults(t *testing.T) { + s := Source{} + s.SetDefaults() +} diff --git a/pkg/apis/eventing/v1alpha1/source_types.go b/pkg/apis/eventing/v1alpha1/source_types.go new file mode 100644 index 00000000000..ebda463fc18 --- /dev/null +++ b/pkg/apis/eventing/v1alpha1/source_types.go @@ -0,0 +1,171 @@ +/* +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 ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/knative/pkg/apis/duck" + duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" + "github.com/knative/pkg/webhook" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +// +genclient +// +genclient:noStatus +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// Source resource Describes a specific configuration (credentials, etc) of a +// source system which can be used to supply events. Sources emit events using a +// channel specified in their status. They cannot receive events. +type Source struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ObjectMeta `json:"metadata,omitempty"` + + // Spec defines the the Provisioner and arguments provided for this Source. + Spec SourceSpec `json:"spec"` + + // Status is the current status of the Source. + // +optional + Status SourceStatus `json:"status,omitempty"` +} + +// Check that Source can be validated and can be defaulted. +var _ webhook.GenericCRD = (*Source)(nil) + +// Check that SourceStatus may have its conditions managed. +var _ duckv1alpha1.ConditionsAccessor = (*SourceStatus)(nil) + +// Check that Source implements the Conditions duck type. +var _ = duck.VerifyType(&Source{}, &duckv1alpha1.Conditions{}) + +// Check that Source implements the Generation duck type. +var emptyGenSource duckv1alpha1.Generation +var _ = duck.VerifyType(&Source{}, &emptyGenSource) + +// And it's Subscribable +var _ = duck.VerifyType(&Subscription{}, &duckv1alpha1.Subscribable{}) + +// SourceSpec is the spec for a Source resource. +type SourceSpec struct { + // TODO: Generation does not work correctly with CRD. They are scrubbed + // by the APIserver (https://github.com/kubernetes/kubernetes/issues/58778) + // So, we add Generation here. Once that gets fixed, remove this and use + // ObjectMeta.Generation instead. + // +optional + Generation int64 `json:"generation,omitempty"` + + // Provisioner is used to create any backing resources and configuration. + // +required + Provisioner *ProvisionerReference `json:"provisioner,omitempty"` + + // Arguments defines the arguments to pass to the Provisioner which provisions + // this Source. + // +optional + Arguments *runtime.RawExtension `json:"arguments,omitempty"` + + // Specify an existing channel to use to emit events. If empty, create a new + // Channel using the cluster/namespace default. + // + // This object must fulfill the Channelable contract. + // + // You can specify only the following fields of the ObjectReference: + // - Kind + // - APIVersion + // - Name + // Currently Kind must be "Channel" and + // APIVersion must be "eventing.knative.dev/v1alpha1" + // +optional + Channel *corev1.ObjectReference `json:"target,omitempty"` +} + +const ( + // SourceConditionReady has status True when the Source is ready to send events. + SourceConditionReady = duckv1alpha1.ConditionReady + + // SourceConditionProvisioned has status True when the Source's backing + // resources have been provisioned. + SourceConditionProvisioned duckv1alpha1.ConditionType = "Provisioned" +) + +var sourceCondSet = duckv1alpha1.NewLivingConditionSet(SourceConditionProvisioned) + +// SourceStatus is the status for a Source resource +type SourceStatus struct { + // Conditions holds the state of a source at a point in time. + // +optional + // +patchMergeKey=type + // +patchStrategy=merge + Conditions duckv1alpha1.Conditions `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"` + + // ObservedGeneration is the 'Generation' of the Source that + // was last reconciled by the controller. + // +optional + ObservedGeneration int64 `json:"observedGeneration,omitempty"` + + // Source might be Subscribable. This points to the Channelable object. + Subscribable duckv1alpha1.Subscribable `json:"subscribable,omitempty"` +} + +// GetCondition returns the condition currently associated with the given type, or nil. +func (ss *SourceStatus) GetCondition(t duckv1alpha1.ConditionType) *duckv1alpha1.Condition { + return sourceCondSet.Manage(ss).GetCondition(t) +} + +// GetConditions returns the Conditions array. This enables generic handling of +// conditions by implementing the duckv1alpha1.Conditions interface. +func (ss *SourceStatus) GetConditions() duckv1alpha1.Conditions { + return ss.Conditions +} + +// IsReady returns true if the resource is ready overall. +func (ss *SourceStatus) IsReady() bool { + return sourceCondSet.Manage(ss).IsHappy() +} + +// InitializeConditions sets relevant unset conditions to Unknown state. +func (ss *SourceStatus) InitializeConditions() { + sourceCondSet.Manage(ss).InitializeConditions() +} + +// MarkProvisioned sets the condition that the source has had its backing resources created. +func (ss *SourceStatus) MarkProvisioned() { + sourceCondSet.Manage(ss).MarkTrue(SourceConditionProvisioned) +} + +// MarkDeprovisioned sets the condition that the source has had its backing resources removed. +func (ss *SourceStatus) MarkDeprovisioned(reason, messageFormat string, messageA ...interface{}) { + sourceCondSet.Manage(ss).MarkFalse(SourceConditionProvisioned, reason, messageFormat, messageA) +} + +// SetConditions sets the Conditions array. This enables generic handling of +// conditions by implementing the duckv1alpha1.Conditions interface. +func (ss *SourceStatus) SetConditions(conditions duckv1alpha1.Conditions) { + ss.Conditions = conditions +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// SourceList is a list of Source resources +type SourceList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata"` + + Items []Source `json:"items"` +} diff --git a/pkg/apis/eventing/v1alpha1/source_types_test.go b/pkg/apis/eventing/v1alpha1/source_types_test.go new file mode 100644 index 00000000000..1ef8374ca09 --- /dev/null +++ b/pkg/apis/eventing/v1alpha1/source_types_test.go @@ -0,0 +1,154 @@ +/* +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" +) + +func TestSourceStatusIsReady(t *testing.T) { + tests := []struct { + name string + s *SourceStatus + want bool + }{{ + name: "uninitialized", + s: &SourceStatus{}, + want: false, + }, { + name: "initialized", + s: func() *SourceStatus { + s := &SourceStatus{} + s.InitializeConditions() + return s + }(), + want: false, + }, { + name: "ready true condition", + s: &SourceStatus{ + Conditions: []duckv1alpha1.Condition{{ + Type: SourceConditionReady, + Status: corev1.ConditionTrue, + }, { + Type: SourceConditionProvisioned, + Status: corev1.ConditionTrue, + }}, + }, + want: true, + }, { + name: "ready false condition", + s: &SourceStatus{ + Conditions: []duckv1alpha1.Condition{{ + Type: SourceConditionReady, + Status: corev1.ConditionFalse, + }, { + Type: SourceConditionProvisioned, + Status: corev1.ConditionTrue, + }}, + }, + want: false, + }, { + name: "unknown condition", + s: &SourceStatus{ + Conditions: []duckv1alpha1.Condition{{ + Type: "foo", + Status: corev1.ConditionTrue, + }}, + }, + want: false, + }, { + name: "mark provisioned", + s: func() *SourceStatus { + s := &SourceStatus{} + s.InitializeConditions() + s.MarkProvisioned() + return s + }(), + want: true, + }, { + name: "mark deprovisioned", + s: func() *SourceStatus { + s := &SourceStatus{} + s.InitializeConditions() + s.MarkDeprovisioned("Testing", "Just a test") + return s + }(), + want: false, + }} + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := test.s.IsReady() + if diff := cmp.Diff(test.want, got); diff != "" { + t.Errorf("%s: unexpected condition (-want, +got) = %v", test.name, diff) + } + }) + } +} + +func TestSourceStatusGetCondition(t *testing.T) { + tests := []struct { + name string + s *SourceStatus + condQuery duckv1alpha1.ConditionType + want *duckv1alpha1.Condition + }{{ + name: "single condition", + s: &SourceStatus{ + Conditions: []duckv1alpha1.Condition{ + condReady, + }, + }, + condQuery: duckv1alpha1.ConditionReady, + want: &condReady, + }, { + name: "unknown condition", + s: &SourceStatus{ + Conditions: []duckv1alpha1.Condition{ + condReady, + condUnprovisioned, + }, + }, + condQuery: duckv1alpha1.ConditionType("foo"), + want: nil, + }} + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := test.s.GetCondition(test.condQuery) + if diff := cmp.Diff(test.want, got); diff != "" { + t.Errorf("unexpected condition (-want, +got) = %v", diff) + } + }) + } +} + +func TestSourceGetSetConditions(t *testing.T) { + c := &Source{ + Status: SourceStatus{}, + } + want := duckv1alpha1.Conditions{condReady} + c.Status.SetConditions(want) + got := c.Status.GetConditions() + if diff := cmp.Diff(want, got); diff != "" { + t.Errorf("unexpected conditions (-want, +got) = %v", diff) + } +} diff --git a/pkg/apis/eventing/v1alpha1/source_validation.go b/pkg/apis/eventing/v1alpha1/source_validation.go new file mode 100644 index 00000000000..5876a2a108c --- /dev/null +++ b/pkg/apis/eventing/v1alpha1/source_validation.go @@ -0,0 +1,43 @@ +/* +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/knative/pkg/apis" + "k8s.io/apimachinery/pkg/api/equality" +) + +// Validate validates the Source resource. +func (s *Source) Validate() *apis.FieldError { + return s.Spec.Validate().ViaField("spec") +} + +// Validate validates the Source spec +func (ss *SourceSpec) Validate() *apis.FieldError { + if equality.Semantic.DeepEqual(ss, &SourceSpec{}) { + return apis.ErrMissingField("provisioner") + } + var errs *apis.FieldError + + if ss.Channel != nil && !isChannelableEmpty(*ss.Channel) { + errs = errs.Also(isValidChannelable(*ss.Channel).ViaField("channel")) + } + + // TODO: could validate that arguments are json if that is a requirement. + + return errs +} diff --git a/pkg/apis/eventing/v1alpha1/source_validation_test.go b/pkg/apis/eventing/v1alpha1/source_validation_test.go new file mode 100644 index 00000000000..212a24ad9a3 --- /dev/null +++ b/pkg/apis/eventing/v1alpha1/source_validation_test.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 v1alpha1 + +import ( + "testing" + + "github.com/knative/pkg/apis" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +func TestSourceValidate(t *testing.T) { + tests := []CRDTest{{ + name: "empty", + cr: &Source{ + Spec: SourceSpec{}, + }, + want: apis.ErrMissingField("spec.provisioner"), + }, { + name: "minimum valid", + cr: &Source{ + Spec: SourceSpec{ + Provisioner: &ProvisionerReference{ + Ref: &corev1.ObjectReference{ + Name: "foo", + }, + }, + }, + }, + }, { + name: "full valid", + cr: &Source{ + Spec: SourceSpec{ + Provisioner: &ProvisionerReference{ + Ref: &corev1.ObjectReference{ + Name: "foo", + }, + }, + Arguments: &runtime.RawExtension{ + Raw: []byte(`{"foo":"baz"}`), + }, + Channel: &corev1.ObjectReference{ + Name: "bar", + Kind: "Channel", + APIVersion: "eventing.knative.dev/v1alpha1", + }, + }, + }, + }, { + name: "invalid, set extra channel parameters", + cr: &Source{ + Spec: SourceSpec{ + Provisioner: &ProvisionerReference{ + Ref: &corev1.ObjectReference{ + Name: "foo", + }, + }, + Channel: &corev1.ObjectReference{ + Name: "bar", + Kind: "Channel", + APIVersion: "eventing.knative.dev/v1alpha1", + ResourceVersion: "SoMad", + }, + }, + }, + want: &apis.FieldError{ + Message: "must not set the field(s)", + Paths: []string{"spec.channel.ResourceVersion"}, + Details: "only name, apiVersion and kind are supported fields", + }, + }, { + name: "invalid, set extra channel as not a channel", + cr: &Source{ + Spec: SourceSpec{ + Provisioner: &ProvisionerReference{ + Ref: &corev1.ObjectReference{ + Name: "foo", + }, + }, + Channel: &corev1.ObjectReference{ + Name: "backwards", + Kind: "lennahC", + APIVersion: "eventing.knative.dev/v1alpha1", + }, + }, + }, + want: &apis.FieldError{ + Message: "invalid value \"lennahC\"", + Paths: []string{"spec.channel.kind"}, + Details: "only 'Channel' kind is allowed", + }, + }} + + doValidateTest(t, tests) +} diff --git a/pkg/apis/eventing/v1alpha1/subscribable_channelable_validation.go b/pkg/apis/eventing/v1alpha1/subscribable_channelable_validation.go new file mode 100644 index 00000000000..fee643e1a84 --- /dev/null +++ b/pkg/apis/eventing/v1alpha1/subscribable_channelable_validation.go @@ -0,0 +1,126 @@ +/* +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 ( + "reflect" + + "github.com/google/go-cmp/cmp" + "github.com/knative/pkg/apis" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/equality" +) + +func isSubscribableEmpty(f corev1.ObjectReference) bool { + return equality.Semantic.DeepEqual(f, corev1.ObjectReference{}) +} + +// Valid from only contains the following fields: +// - Kind == 'Channel' || 'Source' +// - APIVersion == 'eventing.knative.dev/v1alpha1' +// - Name == not empty +func isValidSubscribable(f corev1.ObjectReference) *apis.FieldError { + errs := isValidObjectReference(f) + + if f.Kind != "Channel" && f.Kind != "Source" { + fe := apis.ErrInvalidValue(f.Kind, "kind") + fe.Paths = []string{"kind"} + fe.Details = "only 'Channel' or 'Source' kind is allowed" + errs = errs.Also(fe) + } + if f.APIVersion != "eventing.knative.dev/v1alpha1" { + fe := apis.ErrInvalidValue(f.APIVersion, "apiVersion") + fe.Details = "only eventing.knative.dev/v1alpha1 is allowed for apiVersion" + errs = errs.Also(fe) + } + return errs +} + +func isChannelableEmpty(f corev1.ObjectReference) bool { + return equality.Semantic.DeepEqual(f, corev1.ObjectReference{}) +} + +// Valid from only contains the following fields: +// - Kind == 'Channel' +// - APIVersion == 'eventing.knative.dev/v1alpha1' +// - Name == not empty +func isValidChannelable(f corev1.ObjectReference) *apis.FieldError { + errs := isValidObjectReference(f) + + if f.Kind != "Channel" { + fe := apis.ErrInvalidValue(f.Kind, "kind") + fe.Paths = []string{"kind"} + fe.Details = "only 'Channel' kind is allowed" + errs = errs.Also(fe) + } + if f.APIVersion != "eventing.knative.dev/v1alpha1" { + fe := apis.ErrInvalidValue(f.APIVersion, "apiVersion") + fe.Details = "only eventing.knative.dev/v1alpha1 is allowed for apiVersion" + errs = errs.Also(fe) + } + return errs +} + +func isValidObjectReference(f corev1.ObjectReference) *apis.FieldError { + return checkRequiredObjectReferenceFields(f). + Also(checkDisallowedObjectReferenceFields(f)) +} + +// Check the corev1.ObjectReference to make sure it has the required fields. They +// are not checked for anything more except that they are set. +func checkRequiredObjectReferenceFields(f corev1.ObjectReference) *apis.FieldError { + var errs *apis.FieldError + if f.Name == "" { + errs = errs.Also(apis.ErrMissingField("name")) + } + if f.APIVersion == "" { + errs = errs.Also(apis.ErrMissingField("apiVersion")) + } + if f.Kind == "" { + errs = errs.Also(apis.ErrMissingField("kind")) + } + return errs +} + +// Check the corev1.ObjectReference to make sure it only has the following fields set: +// Name, Kind, APIVersion +// If any other fields are set and is not the Zero value, returns an apis.FieldError +// with the fieldpaths for all those fields. +func checkDisallowedObjectReferenceFields(f corev1.ObjectReference) *apis.FieldError { + disallowedFields := []string{} + // See if there are any fields that have been set that should not be. + // TODO: Hoist this kind of stuff into pkg repository. + s := reflect.ValueOf(f) + typeOf := s.Type() + for i := 0; i < s.NumField(); i++ { + field := s.Field(i) + fieldName := typeOf.Field(i).Name + if fieldName == "Name" || fieldName == "Kind" || fieldName == "APIVersion" { + continue + } + if !cmp.Equal(field.Interface(), reflect.Zero(field.Type()).Interface()) { + disallowedFields = append(disallowedFields, fieldName) + } + } + if len(disallowedFields) > 0 { + fe := apis.ErrDisallowedFields(disallowedFields...) + fe.Details = "only name, apiVersion and kind are supported fields" + return fe + } + return nil + +} diff --git a/pkg/apis/eventing/v1alpha1/subscription_validation.go b/pkg/apis/eventing/v1alpha1/subscription_validation.go index b06068be966..c84d223be5b 100644 --- a/pkg/apis/eventing/v1alpha1/subscription_validation.go +++ b/pkg/apis/eventing/v1alpha1/subscription_validation.go @@ -17,8 +17,6 @@ limitations under the License. package v1alpha1 import ( - "reflect" - "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" "github.com/knative/pkg/apis" @@ -88,7 +86,7 @@ func isValidCallable(c Callable) *apis.FieldError { } func isFromEmpty(f corev1.ObjectReference) bool { - return equality.Semantic.DeepEqual(f, corev1.ObjectReference{}) + return isSubscribableEmpty(f) } // Valid from only contains the following fields: @@ -96,20 +94,7 @@ func isFromEmpty(f corev1.ObjectReference) bool { // - APIVersion == 'eventing.knative.dev/v1alpha1' // - Name == not empty func isValidFrom(f corev1.ObjectReference) *apis.FieldError { - errs := isValidObjectReference(f) - - if f.Kind != "Channel" { - fe := apis.ErrInvalidValue(f.Kind, "kind") - fe.Paths = []string{"kind"} - fe.Details = "only 'Channel' kind is allowed" - errs = errs.Also(fe) - } - if f.APIVersion != "eventing.knative.dev/v1alpha1" { - fe := apis.ErrInvalidValue(f.APIVersion, "apiVersion") - fe.Details = "only eventing.knative.dev/v1alpha1 is allowed for apiVersion" - errs = errs.Also(fe) - } - return errs + return isValidSubscribable(f) } func isResultStrategyNilOrEmpty(r *ResultStrategy) bool { @@ -135,56 +120,6 @@ func isValidResultStrategy(r ResultStrategy) *apis.FieldError { return nil } -func isValidObjectReference(f corev1.ObjectReference) *apis.FieldError { - return checkRequiredFields(f). - Also(checkDisallowedFields(f)) -} - -// Check the corev1.ObjectReference to make sure it has the required fields. They -// are not checked for anything more except that they are set. -func checkRequiredFields(f corev1.ObjectReference) *apis.FieldError { - var errs *apis.FieldError - if f.Name == "" { - errs = errs.Also(apis.ErrMissingField("name")) - } - if f.APIVersion == "" { - errs = errs.Also(apis.ErrMissingField("apiVersion")) - } - if f.Kind == "" { - errs = errs.Also(apis.ErrMissingField("kind")) - } - return errs -} - -// Check the corev1.ObjectReference to make sure it only has the following fields set: -// Name, Kind, APIVersion -// If any other fields are set and is not the Zero value, returns an apis.FieldError -// with the fieldpaths for all those fields. -func checkDisallowedFields(f corev1.ObjectReference) *apis.FieldError { - disallowedFields := []string{} - // See if there are any fields that have been set that should not be. - // TODO: Hoist this kind of stuff into pkg repository. - s := reflect.ValueOf(f) - typeOf := s.Type() - for i := 0; i < s.NumField(); i++ { - field := s.Field(i) - fieldName := typeOf.Field(i).Name - if fieldName == "Name" || fieldName == "Kind" || fieldName == "APIVersion" { - continue - } - if !cmp.Equal(field.Interface(), reflect.Zero(field.Type()).Interface()) { - disallowedFields = append(disallowedFields, fieldName) - } - } - if len(disallowedFields) > 0 { - fe := apis.ErrDisallowedFields(disallowedFields...) - fe.Details = "only name, apiVersion and kind are supported fields" - return fe - } - return nil - -} - func (current *Subscription) CheckImmutableFields(og apis.Immutable) *apis.FieldError { original, ok := og.(*Subscription) if !ok { diff --git a/pkg/apis/eventing/v1alpha1/subscription_validation_test.go b/pkg/apis/eventing/v1alpha1/subscription_validation_test.go index 7d9b9dc1711..7d82bd3ed35 100644 --- a/pkg/apis/eventing/v1alpha1/subscription_validation_test.go +++ b/pkg/apis/eventing/v1alpha1/subscription_validation_test.go @@ -431,7 +431,7 @@ func TestValidFrom(t *testing.T) { }, want: func() *apis.FieldError { fe := apis.ErrInvalidValue("", "kind") - fe.Details = "only 'Channel' kind is allowed" + fe.Details = "only 'Channel' or 'Source' kind is allowed" return apis.ErrMissingField("kind").Also(fe) }(), }, { @@ -443,7 +443,7 @@ func TestValidFrom(t *testing.T) { }, want: func() *apis.FieldError { fe := apis.ErrInvalidValue("subscription", "kind") - fe.Details = "only 'Channel' kind is allowed" + fe.Details = "only 'Channel' or 'Source' kind is allowed" return fe }(), }, { diff --git a/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go index 04144e69030..dcbd9410622 100644 --- a/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go @@ -340,6 +340,134 @@ func (in *ResultStrategy) DeepCopy() *ResultStrategy { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Source) DeepCopyInto(out *Source) { + *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 Source. +func (in *Source) DeepCopy() *Source { + if in == nil { + return nil + } + out := new(Source) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Source) 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 *SourceList) DeepCopyInto(out *SourceList) { + *out = *in + out.TypeMeta = in.TypeMeta + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Source, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SourceList. +func (in *SourceList) DeepCopy() *SourceList { + if in == nil { + return nil + } + out := new(SourceList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *SourceList) 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 *SourceSpec) DeepCopyInto(out *SourceSpec) { + *out = *in + if in.Provisioner != nil { + in, out := &in.Provisioner, &out.Provisioner + if *in == nil { + *out = nil + } else { + *out = new(ProvisionerReference) + (*in).DeepCopyInto(*out) + } + } + if in.Arguments != nil { + in, out := &in.Arguments, &out.Arguments + if *in == nil { + *out = nil + } else { + *out = new(runtime.RawExtension) + (*in).DeepCopyInto(*out) + } + } + if in.Channel != nil { + in, out := &in.Channel, &out.Channel + if *in == nil { + *out = nil + } else { + *out = new(v1.ObjectReference) + **out = **in + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SourceSpec. +func (in *SourceSpec) DeepCopy() *SourceSpec { + if in == nil { + return nil + } + out := new(SourceSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SourceStatus) DeepCopyInto(out *SourceStatus) { + *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]) + } + } + out.Subscribable = in.Subscribable + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SourceStatus. +func (in *SourceStatus) DeepCopy() *SourceStatus { + if in == nil { + return nil + } + out := new(SourceStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Subscription) DeepCopyInto(out *Subscription) { *out = *in 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 3d84eebe8e4..c9474ed0042 100644 --- a/pkg/client/clientset/versioned/typed/eventing/v1alpha1/eventing_client.go +++ b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/eventing_client.go @@ -29,6 +29,7 @@ type EventingV1alpha1Interface interface { RESTClient() rest.Interface ChannelsGetter ClusterProvisionersGetter + SourcesGetter SubscriptionsGetter } @@ -45,6 +46,10 @@ func (c *EventingV1alpha1Client) ClusterProvisioners() ClusterProvisionerInterfa return newClusterProvisioners(c) } +func (c *EventingV1alpha1Client) Sources(namespace string) SourceInterface { + return newSources(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 0127acc10fb..dfd67eea8b1 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 @@ -36,6 +36,10 @@ func (c *FakeEventingV1alpha1) ClusterProvisioners() v1alpha1.ClusterProvisioner return &FakeClusterProvisioners{c} } +func (c *FakeEventingV1alpha1) Sources(namespace string) v1alpha1.SourceInterface { + return &FakeSources{c, namespace} +} + func (c *FakeEventingV1alpha1) Subscriptions(namespace string) v1alpha1.SubscriptionInterface { return &FakeSubscriptions{c, namespace} } diff --git a/pkg/client/clientset/versioned/typed/eventing/v1alpha1/fake/fake_source.go b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/fake/fake_source.go new file mode 100644 index 00000000000..7fa9395eaa4 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/fake/fake_source.go @@ -0,0 +1,128 @@ +/* +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" +) + +// FakeSources implements SourceInterface +type FakeSources struct { + Fake *FakeEventingV1alpha1 + ns string +} + +var sourcesResource = schema.GroupVersionResource{Group: "eventing.knative.dev", Version: "v1alpha1", Resource: "sources"} + +var sourcesKind = schema.GroupVersionKind{Group: "eventing.knative.dev", Version: "v1alpha1", Kind: "Source"} + +// Get takes name of the source, and returns the corresponding source object, and an error if there is any. +func (c *FakeSources) Get(name string, options v1.GetOptions) (result *v1alpha1.Source, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(sourcesResource, c.ns, name), &v1alpha1.Source{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.Source), err +} + +// List takes label and field selectors, and returns the list of Sources that match those selectors. +func (c *FakeSources) List(opts v1.ListOptions) (result *v1alpha1.SourceList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(sourcesResource, sourcesKind, c.ns, opts), &v1alpha1.SourceList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.SourceList{ListMeta: obj.(*v1alpha1.SourceList).ListMeta} + for _, item := range obj.(*v1alpha1.SourceList).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 sources. +func (c *FakeSources) Watch(opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(sourcesResource, c.ns, opts)) + +} + +// Create takes the representation of a source and creates it. Returns the server's representation of the source, and an error, if there is any. +func (c *FakeSources) Create(source *v1alpha1.Source) (result *v1alpha1.Source, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(sourcesResource, c.ns, source), &v1alpha1.Source{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.Source), err +} + +// Update takes the representation of a source and updates it. Returns the server's representation of the source, and an error, if there is any. +func (c *FakeSources) Update(source *v1alpha1.Source) (result *v1alpha1.Source, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(sourcesResource, c.ns, source), &v1alpha1.Source{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.Source), err +} + +// Delete takes name of the source and deletes it. Returns an error if one occurs. +func (c *FakeSources) Delete(name string, options *v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteAction(sourcesResource, c.ns, name), &v1alpha1.Source{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeSources) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(sourcesResource, c.ns, listOptions) + + _, err := c.Fake.Invokes(action, &v1alpha1.SourceList{}) + return err +} + +// Patch applies the patch and returns the patched source. +func (c *FakeSources) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.Source, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(sourcesResource, c.ns, name, data, subresources...), &v1alpha1.Source{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.Source), 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 2d119a1cc27..121200ef9f9 100644 --- a/pkg/client/clientset/versioned/typed/eventing/v1alpha1/generated_expansion.go +++ b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/generated_expansion.go @@ -22,4 +22,6 @@ type ChannelExpansion interface{} type ClusterProvisionerExpansion interface{} +type SourceExpansion interface{} + type SubscriptionExpansion interface{} diff --git a/pkg/client/clientset/versioned/typed/eventing/v1alpha1/source.go b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/source.go new file mode 100644 index 00000000000..f0a4a8a74f7 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/source.go @@ -0,0 +1,157 @@ +/* +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" +) + +// SourcesGetter has a method to return a SourceInterface. +// A group's client should implement this interface. +type SourcesGetter interface { + Sources(namespace string) SourceInterface +} + +// SourceInterface has methods to work with Source resources. +type SourceInterface interface { + Create(*v1alpha1.Source) (*v1alpha1.Source, error) + Update(*v1alpha1.Source) (*v1alpha1.Source, error) + Delete(name string, options *v1.DeleteOptions) error + DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error + Get(name string, options v1.GetOptions) (*v1alpha1.Source, error) + List(opts v1.ListOptions) (*v1alpha1.SourceList, error) + Watch(opts v1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.Source, err error) + SourceExpansion +} + +// sources implements SourceInterface +type sources struct { + client rest.Interface + ns string +} + +// newSources returns a Sources +func newSources(c *EventingV1alpha1Client, namespace string) *sources { + return &sources{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the source, and returns the corresponding source object, and an error if there is any. +func (c *sources) Get(name string, options v1.GetOptions) (result *v1alpha1.Source, err error) { + result = &v1alpha1.Source{} + err = c.client.Get(). + Namespace(c.ns). + Resource("sources"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of Sources that match those selectors. +func (c *sources) List(opts v1.ListOptions) (result *v1alpha1.SourceList, err error) { + result = &v1alpha1.SourceList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("sources"). + VersionedParams(&opts, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested sources. +func (c *sources) Watch(opts v1.ListOptions) (watch.Interface, error) { + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("sources"). + VersionedParams(&opts, scheme.ParameterCodec). + Watch() +} + +// Create takes the representation of a source and creates it. Returns the server's representation of the source, and an error, if there is any. +func (c *sources) Create(source *v1alpha1.Source) (result *v1alpha1.Source, err error) { + result = &v1alpha1.Source{} + err = c.client.Post(). + Namespace(c.ns). + Resource("sources"). + Body(source). + Do(). + Into(result) + return +} + +// Update takes the representation of a source and updates it. Returns the server's representation of the source, and an error, if there is any. +func (c *sources) Update(source *v1alpha1.Source) (result *v1alpha1.Source, err error) { + result = &v1alpha1.Source{} + err = c.client.Put(). + Namespace(c.ns). + Resource("sources"). + Name(source.Name). + Body(source). + Do(). + Into(result) + return +} + +// Delete takes name of the source and deletes it. Returns an error if one occurs. +func (c *sources) Delete(name string, options *v1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("sources"). + Name(name). + Body(options). + Do(). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *sources) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("sources"). + VersionedParams(&listOptions, scheme.ParameterCodec). + Body(options). + Do(). + Error() +} + +// Patch applies the patch and returns the patched source. +func (c *sources) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.Source, err error) { + result = &v1alpha1.Source{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("sources"). + 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 1fd4c99c7dc..2a44cf0f052 100644 --- a/pkg/client/informers/externalversions/eventing/v1alpha1/interface.go +++ b/pkg/client/informers/externalversions/eventing/v1alpha1/interface.go @@ -28,6 +28,8 @@ type Interface interface { Channels() ChannelInformer // ClusterProvisioners returns a ClusterProvisionerInformer. ClusterProvisioners() ClusterProvisionerInformer + // Sources returns a SourceInformer. + Sources() SourceInformer // Subscriptions returns a SubscriptionInformer. Subscriptions() SubscriptionInformer } @@ -53,6 +55,11 @@ func (v *version) ClusterProvisioners() ClusterProvisionerInformer { return &clusterProvisionerInformer{factory: v.factory, tweakListOptions: v.tweakListOptions} } +// Sources returns a SourceInformer. +func (v *version) Sources() SourceInformer { + return &sourceInformer{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/eventing/v1alpha1/source.go b/pkg/client/informers/externalversions/eventing/v1alpha1/source.go new file mode 100644 index 00000000000..eb06180eed1 --- /dev/null +++ b/pkg/client/informers/externalversions/eventing/v1alpha1/source.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" +) + +// SourceInformer provides access to a shared informer and lister for +// Sources. +type SourceInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1alpha1.SourceLister +} + +type sourceInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewSourceInformer constructs a new informer for Source 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 NewSourceInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredSourceInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredSourceInformer constructs a new informer for Source 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 NewFilteredSourceInformer(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().Sources(namespace).List(options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.EventingV1alpha1().Sources(namespace).Watch(options) + }, + }, + &eventing_v1alpha1.Source{}, + resyncPeriod, + indexers, + ) +} + +func (f *sourceInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredSourceInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *sourceInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&eventing_v1alpha1.Source{}, f.defaultInformer) +} + +func (f *sourceInformer) Lister() v1alpha1.SourceLister { + return v1alpha1.NewSourceLister(f.Informer().GetIndexer()) +} diff --git a/pkg/client/informers/externalversions/generic.go b/pkg/client/informers/externalversions/generic.go index 521a45e5029..64978278fda 100644 --- a/pkg/client/informers/externalversions/generic.go +++ b/pkg/client/informers/externalversions/generic.go @@ -70,6 +70,8 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource return &genericInformer{resource: resource.GroupResource(), informer: f.Eventing().V1alpha1().Channels().Informer()}, nil case eventing_v1alpha1.SchemeGroupVersion.WithResource("clusterprovisioners"): return &genericInformer{resource: resource.GroupResource(), informer: f.Eventing().V1alpha1().ClusterProvisioners().Informer()}, nil + case eventing_v1alpha1.SchemeGroupVersion.WithResource("sources"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Eventing().V1alpha1().Sources().Informer()}, nil case eventing_v1alpha1.SchemeGroupVersion.WithResource("subscriptions"): return &genericInformer{resource: resource.GroupResource(), informer: f.Eventing().V1alpha1().Subscriptions().Informer()}, nil diff --git a/pkg/client/listers/eventing/v1alpha1/expansion_generated.go b/pkg/client/listers/eventing/v1alpha1/expansion_generated.go index abc32a5ee74..f3854a6804d 100644 --- a/pkg/client/listers/eventing/v1alpha1/expansion_generated.go +++ b/pkg/client/listers/eventing/v1alpha1/expansion_generated.go @@ -30,6 +30,14 @@ type ChannelNamespaceListerExpansion interface{} // ClusterProvisionerLister. type ClusterProvisionerListerExpansion interface{} +// SourceListerExpansion allows custom methods to be added to +// SourceLister. +type SourceListerExpansion interface{} + +// SourceNamespaceListerExpansion allows custom methods to be added to +// SourceNamespaceLister. +type SourceNamespaceListerExpansion interface{} + // SubscriptionListerExpansion allows custom methods to be added to // SubscriptionLister. type SubscriptionListerExpansion interface{} diff --git a/pkg/client/listers/eventing/v1alpha1/source.go b/pkg/client/listers/eventing/v1alpha1/source.go new file mode 100644 index 00000000000..ec5c3a667ba --- /dev/null +++ b/pkg/client/listers/eventing/v1alpha1/source.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" +) + +// SourceLister helps list Sources. +type SourceLister interface { + // List lists all Sources in the indexer. + List(selector labels.Selector) (ret []*v1alpha1.Source, err error) + // Sources returns an object that can list and get Sources. + Sources(namespace string) SourceNamespaceLister + SourceListerExpansion +} + +// sourceLister implements the SourceLister interface. +type sourceLister struct { + indexer cache.Indexer +} + +// NewSourceLister returns a new SourceLister. +func NewSourceLister(indexer cache.Indexer) SourceLister { + return &sourceLister{indexer: indexer} +} + +// List lists all Sources in the indexer. +func (s *sourceLister) List(selector labels.Selector) (ret []*v1alpha1.Source, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.Source)) + }) + return ret, err +} + +// Sources returns an object that can list and get Sources. +func (s *sourceLister) Sources(namespace string) SourceNamespaceLister { + return sourceNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// SourceNamespaceLister helps list and get Sources. +type SourceNamespaceLister interface { + // List lists all Sources in the indexer for a given namespace. + List(selector labels.Selector) (ret []*v1alpha1.Source, err error) + // Get retrieves the Source from the indexer for a given namespace and name. + Get(name string) (*v1alpha1.Source, error) + SourceNamespaceListerExpansion +} + +// sourceNamespaceLister implements the SourceNamespaceLister +// interface. +type sourceNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all Sources in the indexer for a given namespace. +func (s sourceNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.Source, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.Source)) + }) + return ret, err +} + +// Get retrieves the Source from the indexer for a given namespace and name. +func (s sourceNamespaceLister) Get(name string) (*v1alpha1.Source, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1alpha1.Resource("source"), name) + } + return obj.(*v1alpha1.Source), nil +}