From a67986dc43ce9b4eaa7ba4de032b0bdba32c77e3 Mon Sep 17 00:00:00 2001 From: Scott Nichols Date: Tue, 23 Apr 2019 09:06:34 -0700 Subject: [PATCH 01/25] Move ContainerSource API. --- config/300-cronjobsource.yaml | 84 ++++ hack/update-codegen.sh | 5 + pkg/apis/sources/register.go | 21 + .../sources/v1alpha1/cron_job_lifecycle.go | 95 +++++ .../v1alpha1/cron_job_lifecycle_test.go | 375 ++++++++++++++++++ pkg/apis/sources/v1alpha1/cron_job_types.go | 83 ++++ pkg/apis/sources/v1alpha1/doc.go | 20 + pkg/apis/sources/v1alpha1/register.go | 53 +++ pkg/apis/sources/v1alpha1/register_test.go | 66 +++ .../sources/v1alpha1/zz_generated.deepcopy.go | 125 ++++++ pkg/client/clientset/versioned/clientset.go | 26 +- .../versioned/fake/clientset_generated.go | 16 +- .../clientset/versioned/fake/register.go | 4 +- .../clientset/versioned/scheme/register.go | 4 +- .../typed/sources/v1alpha1/cronjobsource.go | 174 ++++++++ .../versioned/typed/sources/v1alpha1/doc.go | 20 + .../typed/sources/v1alpha1/fake/doc.go | 20 + .../v1alpha1/fake/fake_cronjobsource.go | 140 +++++++ .../v1alpha1/fake/fake_sources_client.go | 40 ++ .../sources/v1alpha1/generated_expansion.go | 21 + .../typed/sources/v1alpha1/sources_client.go | 90 +++++ .../informers/externalversions/factory.go | 8 +- .../informers/externalversions/generic.go | 16 +- .../externalversions/sources/interface.go | 46 +++ .../sources/v1alpha1/cronjobsource.go | 89 +++++ .../sources/v1alpha1/interface.go | 45 +++ .../listers/sources/v1alpha1/cronjobsource.go | 94 +++++ .../sources/v1alpha1/expansion_generated.go | 27 ++ 28 files changed, 1766 insertions(+), 41 deletions(-) create mode 100644 config/300-cronjobsource.yaml create mode 100644 pkg/apis/sources/register.go create mode 100644 pkg/apis/sources/v1alpha1/cron_job_lifecycle.go create mode 100644 pkg/apis/sources/v1alpha1/cron_job_lifecycle_test.go create mode 100644 pkg/apis/sources/v1alpha1/cron_job_types.go create mode 100644 pkg/apis/sources/v1alpha1/doc.go create mode 100644 pkg/apis/sources/v1alpha1/register.go create mode 100644 pkg/apis/sources/v1alpha1/register_test.go create mode 100644 pkg/apis/sources/v1alpha1/zz_generated.deepcopy.go create mode 100644 pkg/client/clientset/versioned/typed/sources/v1alpha1/cronjobsource.go create mode 100644 pkg/client/clientset/versioned/typed/sources/v1alpha1/doc.go create mode 100644 pkg/client/clientset/versioned/typed/sources/v1alpha1/fake/doc.go create mode 100644 pkg/client/clientset/versioned/typed/sources/v1alpha1/fake/fake_cronjobsource.go create mode 100644 pkg/client/clientset/versioned/typed/sources/v1alpha1/fake/fake_sources_client.go create mode 100644 pkg/client/clientset/versioned/typed/sources/v1alpha1/generated_expansion.go create mode 100644 pkg/client/clientset/versioned/typed/sources/v1alpha1/sources_client.go create mode 100644 pkg/client/informers/externalversions/sources/interface.go create mode 100644 pkg/client/informers/externalversions/sources/v1alpha1/cronjobsource.go create mode 100644 pkg/client/informers/externalversions/sources/v1alpha1/interface.go create mode 100644 pkg/client/listers/sources/v1alpha1/cronjobsource.go create mode 100644 pkg/client/listers/sources/v1alpha1/expansion_generated.go diff --git a/config/300-cronjobsource.yaml b/config/300-cronjobsource.yaml new file mode 100644 index 00000000000..50974d4718e --- /dev/null +++ b/config/300-cronjobsource.yaml @@ -0,0 +1,84 @@ +# 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: + labels: + eventing.knative.dev/source: "true" + knative.dev/crd-install: "true" + name: cronjobsources.sources.eventing.knative.dev +spec: + group: sources.eventing.knative.dev + names: + categories: + - all + - knative + - eventing + - sources + kind: CronJobSource + plural: cronjobsources + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + data: + type: string + schedule: + type: string + serviceAccountName: + type: string + sink: + type: object + required: + - schedule + type: object + status: + properties: + conditions: + items: + properties: + lastTransitionTime: + # we use a string in the stored object but a wrapper object + # at runtime. + type: string + message: + type: string + reason: + type: string + severity: + type: string + status: + type: string + type: + type: string + required: + - type + - status + type: object + type: array + sinkUri: + type: string + type: object + version: v1alpha1 diff --git a/hack/update-codegen.sh b/hack/update-codegen.sh index b651c1fc19a..5f199b25f36 100755 --- a/hack/update-codegen.sh +++ b/hack/update-codegen.sh @@ -31,6 +31,11 @@ ${CODEGEN_PKG}/generate-groups.sh "deepcopy,client,informer,lister" \ "eventing:v1alpha1" \ --go-header-file ${REPO_ROOT_DIR}/hack/boilerplate/boilerplate.go.txt +${CODEGEN_PKG}/generate-groups.sh "deepcopy,client,informer,lister" \ + github.com/knative/eventing/pkg/client github.com/knative/eventing/pkg/apis \ + "sources:v1alpha1" \ + --go-header-file ${REPO_ROOT_DIR}/hack/boilerplate/boilerplate.go.txt + # Only deepcopy the Duck types, as they are not real resources. ${CODEGEN_PKG}/generate-groups.sh "deepcopy" \ github.com/knative/eventing/pkg/client github.com/knative/eventing/pkg/apis \ diff --git a/pkg/apis/sources/register.go b/pkg/apis/sources/register.go new file mode 100644 index 00000000000..4d2a4477695 --- /dev/null +++ b/pkg/apis/sources/register.go @@ -0,0 +1,21 @@ +/* +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 sources + +const ( + GroupName = "sources.eventing.knative.dev" +) diff --git a/pkg/apis/sources/v1alpha1/cron_job_lifecycle.go b/pkg/apis/sources/v1alpha1/cron_job_lifecycle.go new file mode 100644 index 00000000000..3df28a080df --- /dev/null +++ b/pkg/apis/sources/v1alpha1/cron_job_lifecycle.go @@ -0,0 +1,95 @@ +/* +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" +) + +const ( + // CronJobConditionReady has status True when the CronJobSource is ready to send events. + CronJobConditionReady = duckv1alpha1.ConditionReady + + // CronJobConditionValidSchedule has status True when the CronJobSource has been configured with a valid schedule. + CronJobConditionValidSchedule duckv1alpha1.ConditionType = "ValidSchedule" + + // CronJobConditionSinkProvided has status True when the CronJobSource has been configured with a sink target. + CronJobConditionSinkProvided duckv1alpha1.ConditionType = "SinkProvided" + + // CronJobConditionDeployed has status True when the CronJobSource has had it's receive adapter deployment created. + CronJobConditionDeployed duckv1alpha1.ConditionType = "Deployed" +) + +var cronJobSourceCondSet = duckv1alpha1.NewLivingConditionSet( + CronJobConditionValidSchedule, + CronJobConditionSinkProvided, + CronJobConditionDeployed) + +// GetCondition returns the condition currently associated with the given type, or nil. +func (s *CronJobSourceStatus) GetCondition(t duckv1alpha1.ConditionType) *duckv1alpha1.Condition { + return cronJobSourceCondSet.Manage(s).GetCondition(t) +} + +// IsReady returns true if the resource is ready overall. +func (s *CronJobSourceStatus) IsReady() bool { + return cronJobSourceCondSet.Manage(s).IsHappy() +} + +// InitializeConditions sets relevant unset conditions to Unknown state. +func (s *CronJobSourceStatus) InitializeConditions() { + cronJobSourceCondSet.Manage(s).InitializeConditions() +} + +// MarkSchedule sets the condition that the source has a valid schedule configured. +func (s *CronJobSourceStatus) MarkSchedule() { + cronJobSourceCondSet.Manage(s).MarkTrue(CronJobConditionValidSchedule) +} + +// MarkInvalidSchedule sets the condition that the source does not have a valid schedule configured. +func (s *CronJobSourceStatus) MarkInvalidSchedule(reason, messageFormat string, messageA ...interface{}) { + cronJobSourceCondSet.Manage(s).MarkFalse(CronJobConditionValidSchedule, reason, messageFormat, messageA...) +} + +// MarkSink sets the condition that the source has a sink configured. +func (s *CronJobSourceStatus) MarkSink(uri string) { + s.SinkURI = uri + if len(uri) > 0 { + cronJobSourceCondSet.Manage(s).MarkTrue(CronJobConditionSinkProvided) + } else { + cronJobSourceCondSet.Manage(s).MarkUnknown(CronJobConditionSinkProvided, "SinkEmpty", "Sink has resolved to empty.%s", "") + } +} + +// MarkNoSink sets the condition that the source does not have a sink configured. +func (s *CronJobSourceStatus) MarkNoSink(reason, messageFormat string, messageA ...interface{}) { + cronJobSourceCondSet.Manage(s).MarkFalse(CronJobConditionSinkProvided, reason, messageFormat, messageA...) +} + +// MarkDeployed sets the condition that the source has been deployed. +func (s *CronJobSourceStatus) MarkDeployed() { + cronJobSourceCondSet.Manage(s).MarkTrue(CronJobConditionDeployed) +} + +// MarkDeploying sets the condition that the source is deploying. +func (s *CronJobSourceStatus) MarkDeploying(reason, messageFormat string, messageA ...interface{}) { + cronJobSourceCondSet.Manage(s).MarkUnknown(CronJobConditionDeployed, reason, messageFormat, messageA...) +} + +// MarkNotDeployed sets the condition that the source has not been deployed. +func (s *CronJobSourceStatus) MarkNotDeployed(reason, messageFormat string, messageA ...interface{}) { + cronJobSourceCondSet.Manage(s).MarkFalse(CronJobConditionDeployed, reason, messageFormat, messageA...) +} diff --git a/pkg/apis/sources/v1alpha1/cron_job_lifecycle_test.go b/pkg/apis/sources/v1alpha1/cron_job_lifecycle_test.go new file mode 100644 index 00000000000..e7f06ce04c7 --- /dev/null +++ b/pkg/apis/sources/v1alpha1/cron_job_lifecycle_test.go @@ -0,0 +1,375 @@ +/* +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_test + +import ( + "github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" + corev1 "k8s.io/api/core/v1" +) + +func TestCronJobSourceStatusIsReady(t *testing.T) { + tests := []struct { + name string + s *v1alpha1.CronJobSourceStatus + want bool + }{{ + name: "uninitialized", + s: &v1alpha1.CronJobSourceStatus{}, + want: false, + }, { + name: "initialized", + s: func() *v1alpha1.CronJobSourceStatus { + s := &v1alpha1.CronJobSourceStatus{} + s.InitializeConditions() + return s + }(), + want: false, + }, { + name: "mark deployed", + s: func() *v1alpha1.CronJobSourceStatus { + s := &v1alpha1.CronJobSourceStatus{} + s.InitializeConditions() + s.MarkDeployed() + return s + }(), + want: false, + }, { + name: "mark sink", + s: func() *v1alpha1.CronJobSourceStatus { + s := &v1alpha1.CronJobSourceStatus{} + s.InitializeConditions() + s.MarkSink("uri://example") + return s + }(), + want: false, + }, { + name: "mark schedule", + s: func() *v1alpha1.CronJobSourceStatus { + s := &v1alpha1.CronJobSourceStatus{} + s.InitializeConditions() + s.MarkSchedule() + return s + }(), + want: false, + }, { + name: "mark sink and deployed", + s: func() *v1alpha1.CronJobSourceStatus { + s := &v1alpha1.CronJobSourceStatus{} + s.InitializeConditions() + s.MarkSink("uri://example") + s.MarkDeployed() + return s + }(), + want: false, + }, { + name: "mark schedule and sink", + s: func() *v1alpha1.CronJobSourceStatus { + s := &v1alpha1.CronJobSourceStatus{} + s.InitializeConditions() + s.MarkSchedule() + s.MarkSink("uri://example") + return s + }(), + want: false, + }, { + name: "mark schedule, sink and deployed", + s: func() *v1alpha1.CronJobSourceStatus { + s := &v1alpha1.CronJobSourceStatus{} + s.InitializeConditions() + s.MarkSchedule() + s.MarkSink("uri://example") + s.MarkDeployed() + return s + }(), + want: true, + }, { + name: "mark schedule, sink and deployed then not deployed", + s: func() *v1alpha1.CronJobSourceStatus { + s := &v1alpha1.CronJobSourceStatus{} + s.InitializeConditions() + s.MarkSchedule() + s.MarkSink("uri://example") + s.MarkDeployed() + s.MarkNotDeployed("Testing", "") + return s + }(), + want: false, + }, { + name: "mark schedule, sink and not deployed then deploying then deployed", + s: func() *v1alpha1.CronJobSourceStatus { + s := &v1alpha1.CronJobSourceStatus{} + s.InitializeConditions() + s.MarkSchedule() + s.MarkSink("uri://example") + s.MarkNotDeployed("MarkNotDeployed", "") + s.MarkDeploying("MarkDeploying", "") + s.MarkDeployed() + return s + }(), + want: true, + }, { + name: "mark schedule validated, sink empty and deployed", + s: func() *v1alpha1.CronJobSourceStatus { + s := &v1alpha1.CronJobSourceStatus{} + s.InitializeConditions() + s.MarkSchedule() + s.MarkSink("") + s.MarkDeployed() + return s + }(), + want: false, + }, { + name: "mark schedule validated, sink empty and deployed then sink", + s: func() *v1alpha1.CronJobSourceStatus { + s := &v1alpha1.CronJobSourceStatus{} + s.InitializeConditions() + s.MarkSchedule() + s.MarkSink("") + s.MarkDeployed() + s.MarkSink("uri://example") + return s + }(), + want: true, + }} + + 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 TestCronJobSourceStatusGetCondition(t *testing.T) { + tests := []struct { + name string + s *v1alpha1.CronJobSourceStatus + condQuery duckv1alpha1.ConditionType + want *duckv1alpha1.Condition + }{{ + name: "uninitialized", + s: &v1alpha1.CronJobSourceStatus{}, + condQuery: v1alpha1.CronJobConditionReady, + want: nil, + }, { + name: "initialized", + s: func() *v1alpha1.CronJobSourceStatus { + s := &v1alpha1.CronJobSourceStatus{} + s.InitializeConditions() + return s + }(), + condQuery: v1alpha1.CronJobConditionReady, + want: &duckv1alpha1.Condition{ + Type: v1alpha1.CronJobConditionReady, + Status: corev1.ConditionUnknown, + }, + }, { + name: "mark deployed", + s: func() *v1alpha1.CronJobSourceStatus { + s := &v1alpha1.CronJobSourceStatus{} + s.InitializeConditions() + s.MarkDeployed() + return s + }(), + condQuery: v1alpha1.CronJobConditionReady, + want: &duckv1alpha1.Condition{ + Type: v1alpha1.CronJobConditionReady, + Status: corev1.ConditionUnknown, + }, + }, { + name: "mark sink", + s: func() *v1alpha1.CronJobSourceStatus { + s := &v1alpha1.CronJobSourceStatus{} + s.InitializeConditions() + s.MarkSink("uri://example") + return s + }(), + condQuery: v1alpha1.CronJobConditionReady, + want: &duckv1alpha1.Condition{ + Type: v1alpha1.CronJobConditionReady, + Status: corev1.ConditionUnknown, + }, + }, { + name: "mark schedule", + s: func() *v1alpha1.CronJobSourceStatus { + s := &v1alpha1.CronJobSourceStatus{} + s.InitializeConditions() + s.MarkSchedule() + return s + }(), + condQuery: v1alpha1.CronJobConditionReady, + want: &duckv1alpha1.Condition{ + Type: v1alpha1.CronJobConditionReady, + Status: corev1.ConditionUnknown, + }, + }, { + name: "mark schedule, sink and deployed", + s: func() *v1alpha1.CronJobSourceStatus { + s := &v1alpha1.CronJobSourceStatus{} + s.InitializeConditions() + s.MarkSchedule() + s.MarkSink("uri://example") + s.MarkDeployed() + return s + }(), + condQuery: v1alpha1.CronJobConditionReady, + want: &duckv1alpha1.Condition{ + Type: v1alpha1.CronJobConditionReady, + Status: corev1.ConditionTrue, + }, + }, { + name: "mark schedule, sink and deployed then no sink", + s: func() *v1alpha1.CronJobSourceStatus { + s := &v1alpha1.CronJobSourceStatus{} + s.InitializeConditions() + s.MarkSchedule() + s.MarkSink("uri://example") + s.MarkDeployed() + s.MarkNoSink("Testing", "hi%s", "") + return s + }(), + condQuery: v1alpha1.CronJobConditionReady, + want: &duckv1alpha1.Condition{ + Type: v1alpha1.CronJobConditionReady, + Status: corev1.ConditionFalse, + Reason: "Testing", + Message: "hi", + }, + }, { + name: "mark schedule, sink and deployed then invalid schedule", + s: func() *v1alpha1.CronJobSourceStatus { + s := &v1alpha1.CronJobSourceStatus{} + s.InitializeConditions() + s.MarkSchedule() + s.MarkSink("uri://example") + s.MarkDeployed() + s.MarkInvalidSchedule("Testing", "hi%s", "") + return s + }(), + condQuery: v1alpha1.CronJobConditionReady, + want: &duckv1alpha1.Condition{ + Type: v1alpha1.CronJobConditionReady, + Status: corev1.ConditionFalse, + Reason: "Testing", + Message: "hi", + }, + }, { + name: "mark schedule, sink and deployed then deploying", + s: func() *v1alpha1.CronJobSourceStatus { + s := &v1alpha1.CronJobSourceStatus{} + s.InitializeConditions() + s.MarkSchedule() + s.MarkSink("uri://example") + s.MarkDeployed() + s.MarkDeploying("Testing", "hi%s", "") + return s + }(), + condQuery: v1alpha1.CronJobConditionReady, + want: &duckv1alpha1.Condition{ + Type: v1alpha1.CronJobConditionReady, + Status: corev1.ConditionUnknown, + Reason: "Testing", + Message: "hi", + }, + }, { + name: "mark schedule, sink and deployed then not deployed", + s: func() *v1alpha1.CronJobSourceStatus { + s := &v1alpha1.CronJobSourceStatus{} + s.InitializeConditions() + s.MarkSchedule() + s.MarkSink("uri://example") + s.MarkDeployed() + s.MarkNotDeployed("Testing", "hi%s", "") + return s + }(), + condQuery: v1alpha1.CronJobConditionReady, + want: &duckv1alpha1.Condition{ + Type: v1alpha1.CronJobConditionReady, + Status: corev1.ConditionFalse, + Reason: "Testing", + Message: "hi", + }, + }, { + name: "mark schedule, sink and not deployed then deploying then deployed", + s: func() *v1alpha1.CronJobSourceStatus { + s := &v1alpha1.CronJobSourceStatus{} + s.InitializeConditions() + s.MarkSchedule() + s.MarkSink("uri://example") + s.MarkNotDeployed("MarkNotDeployed", "%s", "") + s.MarkDeploying("MarkDeploying", "%s", "") + s.MarkDeployed() + return s + }(), + condQuery: v1alpha1.CronJobConditionReady, + want: &duckv1alpha1.Condition{ + Type: v1alpha1.CronJobConditionReady, + Status: corev1.ConditionTrue, + }, + }, { + name: "mark schedule, sink empty and deployed", + s: func() *v1alpha1.CronJobSourceStatus { + s := &v1alpha1.CronJobSourceStatus{} + s.InitializeConditions() + s.MarkSchedule() + s.MarkSink("") + s.MarkDeployed() + return s + }(), + condQuery: v1alpha1.CronJobConditionReady, + want: &duckv1alpha1.Condition{ + Type: v1alpha1.CronJobConditionReady, + Status: corev1.ConditionUnknown, + Reason: "SinkEmpty", + Message: "Sink has resolved to empty.", + }, + }, { + name: "mark schedule, sink empty and deployed then sink", + s: func() *v1alpha1.CronJobSourceStatus { + s := &v1alpha1.CronJobSourceStatus{} + s.InitializeConditions() + s.MarkSchedule() + s.MarkSink("") + s.MarkDeployed() + s.MarkSink("uri://example") + return s + }(), + condQuery: v1alpha1.CronJobConditionReady, + want: &duckv1alpha1.Condition{ + Type: v1alpha1.CronJobConditionReady, + Status: corev1.ConditionTrue, + }, + }} + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := test.s.GetCondition(test.condQuery) + ignoreTime := cmpopts.IgnoreFields(duckv1alpha1.Condition{}, + "LastTransitionTime", "Severity") + if diff := cmp.Diff(test.want, got, ignoreTime); diff != "" { + t.Errorf("unexpected condition (-want, +got) = %v", diff) + } + }) + } +} diff --git a/pkg/apis/sources/v1alpha1/cron_job_types.go b/pkg/apis/sources/v1alpha1/cron_job_types.go new file mode 100644 index 00000000000..df6f69d9197 --- /dev/null +++ b/pkg/apis/sources/v1alpha1/cron_job_types.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 ( + "github.com/knative/pkg/apis/duck" + duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// CronJobSource is the Schema for the cronjobsources API. +type CronJobSource struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec CronJobSourceSpec `json:"spec,omitempty"` + Status CronJobSourceStatus `json:"status,omitempty"` +} + +// Check that CronJobSource can be validated and can be defaulted. +var _ runtime.Object = (*CronJobSource)(nil) + +// Check that CronJobSource implements the Conditions duck type. +var _ = duck.VerifyType(&CronJobSource{}, &duckv1alpha1.Conditions{}) + +// CronJobSourceSpec defines the desired state of the CronJobSource. +type CronJobSourceSpec struct { + + // Schedule is the cronjob schedule. + // +required + Schedule string `json:"schedule"` + + // Data is the data posted to the target function. + Data string `json:"data,omitempty"` + + // Sink is a reference to an object that will resolve to a domain name to use as the sink. + // +optional + Sink *corev1.ObjectReference `json:"sink,omitempty"` + + // ServiceAccoutName is the name of the ServiceAccount that will be used to run the Receive + // Adapter Deployment. + ServiceAccountName string `json:"serviceAccountName,omitempty"` +} + +// CronJobSourceStatus defines the observed state of CronJobSource. +type CronJobSourceStatus struct { + // 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"` + + // SinkURI is the current active sink URI that has been configured for the CronJobSource. + // +optional + SinkURI string `json:"sinkUri,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// CronJobSourceList contains a list of CronJobSources. +type CronJobSourceList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []CronJobSource `json:"items"` +} diff --git a/pkg/apis/sources/v1alpha1/doc.go b/pkg/apis/sources/v1alpha1/doc.go new file mode 100644 index 00000000000..7d7f6738fbc --- /dev/null +++ b/pkg/apis/sources/v1alpha1/doc.go @@ -0,0 +1,20 @@ +/* +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 contains API Schema definitions for the sources v1alpha1 API group +// +k8s:deepcopy-gen=package +// +groupName=sources.eventing.knative.dev +package v1alpha1 diff --git a/pkg/apis/sources/v1alpha1/register.go b/pkg/apis/sources/v1alpha1/register.go new file mode 100644 index 00000000000..fa8640fc93f --- /dev/null +++ b/pkg/apis/sources/v1alpha1/register.go @@ -0,0 +1,53 @@ +/* +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/eventing/pkg/apis/sources" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +// SchemeGroupVersion is group version used to register these objects +var SchemeGroupVersion = schema.GroupVersion{Group: sources.GroupName, Version: "v1alpha1"} + +// Kind takes an unqualified kind and returns back a Group qualified GroupKind +func Kind(kind string) schema.GroupKind { + return SchemeGroupVersion.WithKind(kind).GroupKind() +} + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +var ( + SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) + AddToScheme = SchemeBuilder.AddToScheme +) + +// Adds the list of known types to Scheme. +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + &CronJobSource{}, + &CronJobSourceList{}, + ) + metav1.AddToGroupVersion(scheme, SchemeGroupVersion) + return nil +} diff --git a/pkg/apis/sources/v1alpha1/register_test.go b/pkg/apis/sources/v1alpha1/register_test.go new file mode 100644 index 00000000000..62893f72be9 --- /dev/null +++ b/pkg/apis/sources/v1alpha1/register_test.go @@ -0,0 +1,66 @@ +/* +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" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func TestResource(t *testing.T) { + want := schema.GroupResource{ + Group: "sources.eventing.knative.dev", + Resource: "foo", + } + + got := Resource("foo") + + if diff := cmp.Diff(want, got); diff != "" { + t.Errorf("unexpected resource (-want, +got) = %v", diff) + } +} + +// Kind takes an unqualified resource and returns a Group qualified GroupKind +func TestKind(t *testing.T) { + want := schema.GroupKind{ + Group: "sources.eventing.knative.dev", + Kind: "kind", + } + + got := Kind("kind") + + if diff := cmp.Diff(want, got); diff != "" { + t.Errorf("unexpected resource (-want, +got) = %v", diff) + } +} + +// TestKnownTypes makes sure that expected types get added. +func TestKnownTypes(t *testing.T) { + scheme := runtime.NewScheme() + addKnownTypes(scheme) + types := scheme.KnownTypes(SchemeGroupVersion) + + for _, name := range []string{ + "CronJobSource", + "CronJobSourceList", + } { + if _, ok := types[name]; !ok { + t.Errorf("Did not find %q as registered type", name) + } + } + +} diff --git a/pkg/apis/sources/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/sources/v1alpha1/zz_generated.deepcopy.go new file mode 100644 index 00000000000..27618a2b621 --- /dev/null +++ b/pkg/apis/sources/v1alpha1/zz_generated.deepcopy.go @@ -0,0 +1,125 @@ +// +build !ignore_autogenerated + +/* +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 deepcopy-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + v1 "k8s.io/api/core/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 *CronJobSource) DeepCopyInto(out *CronJobSource) { + *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 CronJobSource. +func (in *CronJobSource) DeepCopy() *CronJobSource { + if in == nil { + return nil + } + out := new(CronJobSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *CronJobSource) 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 *CronJobSourceList) DeepCopyInto(out *CronJobSourceList) { + *out = *in + out.TypeMeta = in.TypeMeta + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]CronJobSource, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CronJobSourceList. +func (in *CronJobSourceList) DeepCopy() *CronJobSourceList { + if in == nil { + return nil + } + out := new(CronJobSourceList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *CronJobSourceList) 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 *CronJobSourceSpec) DeepCopyInto(out *CronJobSourceSpec) { + *out = *in + if in.Sink != nil { + in, out := &in.Sink, &out.Sink + *out = new(v1.ObjectReference) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CronJobSourceSpec. +func (in *CronJobSourceSpec) DeepCopy() *CronJobSourceSpec { + if in == nil { + return nil + } + out := new(CronJobSourceSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CronJobSourceStatus) DeepCopyInto(out *CronJobSourceStatus) { + *out = *in + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CronJobSourceStatus. +func (in *CronJobSourceStatus) DeepCopy() *CronJobSourceStatus { + if in == nil { + return nil + } + out := new(CronJobSourceStatus) + in.DeepCopyInto(out) + return out +} diff --git a/pkg/client/clientset/versioned/clientset.go b/pkg/client/clientset/versioned/clientset.go index 4f8f6c7c4c3..37423028552 100644 --- a/pkg/client/clientset/versioned/clientset.go +++ b/pkg/client/clientset/versioned/clientset.go @@ -19,7 +19,7 @@ limitations under the License. package versioned import ( - eventingv1alpha1 "github.com/knative/eventing/pkg/client/clientset/versioned/typed/eventing/v1alpha1" + sourcesv1alpha1 "github.com/knative/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha1" discovery "k8s.io/client-go/discovery" rest "k8s.io/client-go/rest" flowcontrol "k8s.io/client-go/util/flowcontrol" @@ -27,27 +27,27 @@ import ( type Interface interface { Discovery() discovery.DiscoveryInterface - EventingV1alpha1() eventingv1alpha1.EventingV1alpha1Interface + SourcesV1alpha1() sourcesv1alpha1.SourcesV1alpha1Interface // Deprecated: please explicitly pick a version if possible. - Eventing() eventingv1alpha1.EventingV1alpha1Interface + Sources() sourcesv1alpha1.SourcesV1alpha1Interface } // Clientset contains the clients for groups. Each group has exactly one // version included in a Clientset. type Clientset struct { *discovery.DiscoveryClient - eventingV1alpha1 *eventingv1alpha1.EventingV1alpha1Client + sourcesV1alpha1 *sourcesv1alpha1.SourcesV1alpha1Client } -// EventingV1alpha1 retrieves the EventingV1alpha1Client -func (c *Clientset) EventingV1alpha1() eventingv1alpha1.EventingV1alpha1Interface { - return c.eventingV1alpha1 +// SourcesV1alpha1 retrieves the SourcesV1alpha1Client +func (c *Clientset) SourcesV1alpha1() sourcesv1alpha1.SourcesV1alpha1Interface { + return c.sourcesV1alpha1 } -// Deprecated: Eventing retrieves the default version of EventingClient. +// Deprecated: Sources retrieves the default version of SourcesClient. // Please explicitly pick a version. -func (c *Clientset) Eventing() eventingv1alpha1.EventingV1alpha1Interface { - return c.eventingV1alpha1 +func (c *Clientset) Sources() sourcesv1alpha1.SourcesV1alpha1Interface { + return c.sourcesV1alpha1 } // Discovery retrieves the DiscoveryClient @@ -66,7 +66,7 @@ func NewForConfig(c *rest.Config) (*Clientset, error) { } var cs Clientset var err error - cs.eventingV1alpha1, err = eventingv1alpha1.NewForConfig(&configShallowCopy) + cs.sourcesV1alpha1, err = sourcesv1alpha1.NewForConfig(&configShallowCopy) if err != nil { return nil, err } @@ -82,7 +82,7 @@ func NewForConfig(c *rest.Config) (*Clientset, error) { // panics if there is an error in the config. func NewForConfigOrDie(c *rest.Config) *Clientset { var cs Clientset - cs.eventingV1alpha1 = eventingv1alpha1.NewForConfigOrDie(c) + cs.sourcesV1alpha1 = sourcesv1alpha1.NewForConfigOrDie(c) cs.DiscoveryClient = discovery.NewDiscoveryClientForConfigOrDie(c) return &cs @@ -91,7 +91,7 @@ func NewForConfigOrDie(c *rest.Config) *Clientset { // New creates a new Clientset for the given RESTClient. func New(c rest.Interface) *Clientset { var cs Clientset - cs.eventingV1alpha1 = eventingv1alpha1.New(c) + cs.sourcesV1alpha1 = sourcesv1alpha1.New(c) cs.DiscoveryClient = discovery.NewDiscoveryClient(c) return &cs diff --git a/pkg/client/clientset/versioned/fake/clientset_generated.go b/pkg/client/clientset/versioned/fake/clientset_generated.go index 0a4b10bfa14..4f40e6e25fe 100644 --- a/pkg/client/clientset/versioned/fake/clientset_generated.go +++ b/pkg/client/clientset/versioned/fake/clientset_generated.go @@ -20,8 +20,8 @@ package fake import ( clientset "github.com/knative/eventing/pkg/client/clientset/versioned" - eventingv1alpha1 "github.com/knative/eventing/pkg/client/clientset/versioned/typed/eventing/v1alpha1" - fakeeventingv1alpha1 "github.com/knative/eventing/pkg/client/clientset/versioned/typed/eventing/v1alpha1/fake" + sourcesv1alpha1 "github.com/knative/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha1" + fakesourcesv1alpha1 "github.com/knative/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha1/fake" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/watch" "k8s.io/client-go/discovery" @@ -71,12 +71,12 @@ func (c *Clientset) Discovery() discovery.DiscoveryInterface { var _ clientset.Interface = &Clientset{} -// EventingV1alpha1 retrieves the EventingV1alpha1Client -func (c *Clientset) EventingV1alpha1() eventingv1alpha1.EventingV1alpha1Interface { - return &fakeeventingv1alpha1.FakeEventingV1alpha1{Fake: &c.Fake} +// SourcesV1alpha1 retrieves the SourcesV1alpha1Client +func (c *Clientset) SourcesV1alpha1() sourcesv1alpha1.SourcesV1alpha1Interface { + return &fakesourcesv1alpha1.FakeSourcesV1alpha1{Fake: &c.Fake} } -// Eventing retrieves the EventingV1alpha1Client -func (c *Clientset) Eventing() eventingv1alpha1.EventingV1alpha1Interface { - return &fakeeventingv1alpha1.FakeEventingV1alpha1{Fake: &c.Fake} +// Sources retrieves the SourcesV1alpha1Client +func (c *Clientset) Sources() sourcesv1alpha1.SourcesV1alpha1Interface { + return &fakesourcesv1alpha1.FakeSourcesV1alpha1{Fake: &c.Fake} } diff --git a/pkg/client/clientset/versioned/fake/register.go b/pkg/client/clientset/versioned/fake/register.go index 60103d7155b..325188a8adf 100644 --- a/pkg/client/clientset/versioned/fake/register.go +++ b/pkg/client/clientset/versioned/fake/register.go @@ -19,7 +19,7 @@ limitations under the License. package fake import ( - eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" + sourcesv1alpha1 "github.com/knative/eventing/pkg/apis/sources/v1alpha1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" schema "k8s.io/apimachinery/pkg/runtime/schema" @@ -31,7 +31,7 @@ var scheme = runtime.NewScheme() var codecs = serializer.NewCodecFactory(scheme) var parameterCodec = runtime.NewParameterCodec(scheme) var localSchemeBuilder = runtime.SchemeBuilder{ - eventingv1alpha1.AddToScheme, + sourcesv1alpha1.AddToScheme, } // AddToScheme adds all types of this clientset into the given scheme. This allows composition diff --git a/pkg/client/clientset/versioned/scheme/register.go b/pkg/client/clientset/versioned/scheme/register.go index a6263f98cb9..b0dd52f43ba 100644 --- a/pkg/client/clientset/versioned/scheme/register.go +++ b/pkg/client/clientset/versioned/scheme/register.go @@ -19,7 +19,7 @@ limitations under the License. package scheme import ( - eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" + sourcesv1alpha1 "github.com/knative/eventing/pkg/apis/sources/v1alpha1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" schema "k8s.io/apimachinery/pkg/runtime/schema" @@ -31,7 +31,7 @@ var Scheme = runtime.NewScheme() var Codecs = serializer.NewCodecFactory(Scheme) var ParameterCodec = runtime.NewParameterCodec(Scheme) var localSchemeBuilder = runtime.SchemeBuilder{ - eventingv1alpha1.AddToScheme, + sourcesv1alpha1.AddToScheme, } // AddToScheme adds all types of this clientset into the given scheme. This allows composition diff --git a/pkg/client/clientset/versioned/typed/sources/v1alpha1/cronjobsource.go b/pkg/client/clientset/versioned/typed/sources/v1alpha1/cronjobsource.go new file mode 100644 index 00000000000..f18f9c8150b --- /dev/null +++ b/pkg/client/clientset/versioned/typed/sources/v1alpha1/cronjobsource.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/sources/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" +) + +// CronJobSourcesGetter has a method to return a CronJobSourceInterface. +// A group's client should implement this interface. +type CronJobSourcesGetter interface { + CronJobSources(namespace string) CronJobSourceInterface +} + +// CronJobSourceInterface has methods to work with CronJobSource resources. +type CronJobSourceInterface interface { + Create(*v1alpha1.CronJobSource) (*v1alpha1.CronJobSource, error) + Update(*v1alpha1.CronJobSource) (*v1alpha1.CronJobSource, error) + UpdateStatus(*v1alpha1.CronJobSource) (*v1alpha1.CronJobSource, error) + Delete(name string, options *v1.DeleteOptions) error + DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error + Get(name string, options v1.GetOptions) (*v1alpha1.CronJobSource, error) + List(opts v1.ListOptions) (*v1alpha1.CronJobSourceList, error) + Watch(opts v1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.CronJobSource, err error) + CronJobSourceExpansion +} + +// cronJobSources implements CronJobSourceInterface +type cronJobSources struct { + client rest.Interface + ns string +} + +// newCronJobSources returns a CronJobSources +func newCronJobSources(c *SourcesV1alpha1Client, namespace string) *cronJobSources { + return &cronJobSources{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the cronJobSource, and returns the corresponding cronJobSource object, and an error if there is any. +func (c *cronJobSources) Get(name string, options v1.GetOptions) (result *v1alpha1.CronJobSource, err error) { + result = &v1alpha1.CronJobSource{} + err = c.client.Get(). + Namespace(c.ns). + Resource("cronjobsources"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of CronJobSources that match those selectors. +func (c *cronJobSources) List(opts v1.ListOptions) (result *v1alpha1.CronJobSourceList, err error) { + result = &v1alpha1.CronJobSourceList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("cronjobsources"). + VersionedParams(&opts, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested cronJobSources. +func (c *cronJobSources) Watch(opts v1.ListOptions) (watch.Interface, error) { + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("cronjobsources"). + VersionedParams(&opts, scheme.ParameterCodec). + Watch() +} + +// Create takes the representation of a cronJobSource and creates it. Returns the server's representation of the cronJobSource, and an error, if there is any. +func (c *cronJobSources) Create(cronJobSource *v1alpha1.CronJobSource) (result *v1alpha1.CronJobSource, err error) { + result = &v1alpha1.CronJobSource{} + err = c.client.Post(). + Namespace(c.ns). + Resource("cronjobsources"). + Body(cronJobSource). + Do(). + Into(result) + return +} + +// Update takes the representation of a cronJobSource and updates it. Returns the server's representation of the cronJobSource, and an error, if there is any. +func (c *cronJobSources) Update(cronJobSource *v1alpha1.CronJobSource) (result *v1alpha1.CronJobSource, err error) { + result = &v1alpha1.CronJobSource{} + err = c.client.Put(). + Namespace(c.ns). + Resource("cronjobsources"). + Name(cronJobSource.Name). + Body(cronJobSource). + 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 *cronJobSources) UpdateStatus(cronJobSource *v1alpha1.CronJobSource) (result *v1alpha1.CronJobSource, err error) { + result = &v1alpha1.CronJobSource{} + err = c.client.Put(). + Namespace(c.ns). + Resource("cronjobsources"). + Name(cronJobSource.Name). + SubResource("status"). + Body(cronJobSource). + Do(). + Into(result) + return +} + +// Delete takes name of the cronJobSource and deletes it. Returns an error if one occurs. +func (c *cronJobSources) Delete(name string, options *v1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("cronjobsources"). + Name(name). + Body(options). + Do(). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *cronJobSources) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("cronjobsources"). + VersionedParams(&listOptions, scheme.ParameterCodec). + Body(options). + Do(). + Error() +} + +// Patch applies the patch and returns the patched cronJobSource. +func (c *cronJobSources) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.CronJobSource, err error) { + result = &v1alpha1.CronJobSource{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("cronjobsources"). + SubResource(subresources...). + Name(name). + Body(data). + Do(). + Into(result) + return +} diff --git a/pkg/client/clientset/versioned/typed/sources/v1alpha1/doc.go b/pkg/client/clientset/versioned/typed/sources/v1alpha1/doc.go new file mode 100644 index 00000000000..75445c17900 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/sources/v1alpha1/doc.go @@ -0,0 +1,20 @@ +/* +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. + +// This package has the automatically generated typed clients. +package v1alpha1 diff --git a/pkg/client/clientset/versioned/typed/sources/v1alpha1/fake/doc.go b/pkg/client/clientset/versioned/typed/sources/v1alpha1/fake/doc.go new file mode 100644 index 00000000000..128aa183a91 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/sources/v1alpha1/fake/doc.go @@ -0,0 +1,20 @@ +/* +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 has the automatically generated clients. +package fake diff --git a/pkg/client/clientset/versioned/typed/sources/v1alpha1/fake/fake_cronjobsource.go b/pkg/client/clientset/versioned/typed/sources/v1alpha1/fake/fake_cronjobsource.go new file mode 100644 index 00000000000..f90c9761f1c --- /dev/null +++ b/pkg/client/clientset/versioned/typed/sources/v1alpha1/fake/fake_cronjobsource.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/sources/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" +) + +// FakeCronJobSources implements CronJobSourceInterface +type FakeCronJobSources struct { + Fake *FakeSourcesV1alpha1 + ns string +} + +var cronjobsourcesResource = schema.GroupVersionResource{Group: "sources.eventing.knative.dev", Version: "v1alpha1", Resource: "cronjobsources"} + +var cronjobsourcesKind = schema.GroupVersionKind{Group: "sources.eventing.knative.dev", Version: "v1alpha1", Kind: "CronJobSource"} + +// Get takes name of the cronJobSource, and returns the corresponding cronJobSource object, and an error if there is any. +func (c *FakeCronJobSources) Get(name string, options v1.GetOptions) (result *v1alpha1.CronJobSource, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(cronjobsourcesResource, c.ns, name), &v1alpha1.CronJobSource{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.CronJobSource), err +} + +// List takes label and field selectors, and returns the list of CronJobSources that match those selectors. +func (c *FakeCronJobSources) List(opts v1.ListOptions) (result *v1alpha1.CronJobSourceList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(cronjobsourcesResource, cronjobsourcesKind, c.ns, opts), &v1alpha1.CronJobSourceList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.CronJobSourceList{ListMeta: obj.(*v1alpha1.CronJobSourceList).ListMeta} + for _, item := range obj.(*v1alpha1.CronJobSourceList).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 cronJobSources. +func (c *FakeCronJobSources) Watch(opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(cronjobsourcesResource, c.ns, opts)) + +} + +// Create takes the representation of a cronJobSource and creates it. Returns the server's representation of the cronJobSource, and an error, if there is any. +func (c *FakeCronJobSources) Create(cronJobSource *v1alpha1.CronJobSource) (result *v1alpha1.CronJobSource, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(cronjobsourcesResource, c.ns, cronJobSource), &v1alpha1.CronJobSource{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.CronJobSource), err +} + +// Update takes the representation of a cronJobSource and updates it. Returns the server's representation of the cronJobSource, and an error, if there is any. +func (c *FakeCronJobSources) Update(cronJobSource *v1alpha1.CronJobSource) (result *v1alpha1.CronJobSource, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(cronjobsourcesResource, c.ns, cronJobSource), &v1alpha1.CronJobSource{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.CronJobSource), 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 *FakeCronJobSources) UpdateStatus(cronJobSource *v1alpha1.CronJobSource) (*v1alpha1.CronJobSource, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(cronjobsourcesResource, "status", c.ns, cronJobSource), &v1alpha1.CronJobSource{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.CronJobSource), err +} + +// Delete takes name of the cronJobSource and deletes it. Returns an error if one occurs. +func (c *FakeCronJobSources) Delete(name string, options *v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteAction(cronjobsourcesResource, c.ns, name), &v1alpha1.CronJobSource{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeCronJobSources) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(cronjobsourcesResource, c.ns, listOptions) + + _, err := c.Fake.Invokes(action, &v1alpha1.CronJobSourceList{}) + return err +} + +// Patch applies the patch and returns the patched cronJobSource. +func (c *FakeCronJobSources) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.CronJobSource, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(cronjobsourcesResource, c.ns, name, data, subresources...), &v1alpha1.CronJobSource{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.CronJobSource), err +} diff --git a/pkg/client/clientset/versioned/typed/sources/v1alpha1/fake/fake_sources_client.go b/pkg/client/clientset/versioned/typed/sources/v1alpha1/fake/fake_sources_client.go new file mode 100644 index 00000000000..14861734bd7 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/sources/v1alpha1/fake/fake_sources_client.go @@ -0,0 +1,40 @@ +/* +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/client/clientset/versioned/typed/sources/v1alpha1" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeSourcesV1alpha1 struct { + *testing.Fake +} + +func (c *FakeSourcesV1alpha1) CronJobSources(namespace string) v1alpha1.CronJobSourceInterface { + return &FakeCronJobSources{c, namespace} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeSourcesV1alpha1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/pkg/client/clientset/versioned/typed/sources/v1alpha1/generated_expansion.go b/pkg/client/clientset/versioned/typed/sources/v1alpha1/generated_expansion.go new file mode 100644 index 00000000000..e11588db657 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/sources/v1alpha1/generated_expansion.go @@ -0,0 +1,21 @@ +/* +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 + +type CronJobSourceExpansion interface{} diff --git a/pkg/client/clientset/versioned/typed/sources/v1alpha1/sources_client.go b/pkg/client/clientset/versioned/typed/sources/v1alpha1/sources_client.go new file mode 100644 index 00000000000..ef301678c43 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/sources/v1alpha1/sources_client.go @@ -0,0 +1,90 @@ +/* +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/sources/v1alpha1" + "github.com/knative/eventing/pkg/client/clientset/versioned/scheme" + serializer "k8s.io/apimachinery/pkg/runtime/serializer" + rest "k8s.io/client-go/rest" +) + +type SourcesV1alpha1Interface interface { + RESTClient() rest.Interface + CronJobSourcesGetter +} + +// SourcesV1alpha1Client is used to interact with features provided by the sources.eventing.knative.dev group. +type SourcesV1alpha1Client struct { + restClient rest.Interface +} + +func (c *SourcesV1alpha1Client) CronJobSources(namespace string) CronJobSourceInterface { + return newCronJobSources(c, namespace) +} + +// NewForConfig creates a new SourcesV1alpha1Client for the given config. +func NewForConfig(c *rest.Config) (*SourcesV1alpha1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + client, err := rest.RESTClientFor(&config) + if err != nil { + return nil, err + } + return &SourcesV1alpha1Client{client}, nil +} + +// NewForConfigOrDie creates a new SourcesV1alpha1Client for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *SourcesV1alpha1Client { + client, err := NewForConfig(c) + if err != nil { + panic(err) + } + return client +} + +// New creates a new SourcesV1alpha1Client for the given RESTClient. +func New(c rest.Interface) *SourcesV1alpha1Client { + return &SourcesV1alpha1Client{c} +} + +func setConfigDefaults(config *rest.Config) error { + gv := v1alpha1.SchemeGroupVersion + config.GroupVersion = &gv + config.APIPath = "/apis" + config.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: scheme.Codecs} + + if config.UserAgent == "" { + config.UserAgent = rest.DefaultKubernetesUserAgent() + } + + return nil +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *SourcesV1alpha1Client) RESTClient() rest.Interface { + if c == nil { + return nil + } + return c.restClient +} diff --git a/pkg/client/informers/externalversions/factory.go b/pkg/client/informers/externalversions/factory.go index 0cde7d2cdd1..90878bd75fe 100644 --- a/pkg/client/informers/externalversions/factory.go +++ b/pkg/client/informers/externalversions/factory.go @@ -24,8 +24,8 @@ import ( time "time" versioned "github.com/knative/eventing/pkg/client/clientset/versioned" - eventing "github.com/knative/eventing/pkg/client/informers/externalversions/eventing" internalinterfaces "github.com/knative/eventing/pkg/client/informers/externalversions/internalinterfaces" + sources "github.com/knative/eventing/pkg/client/informers/externalversions/sources" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" schema "k8s.io/apimachinery/pkg/runtime/schema" @@ -172,9 +172,9 @@ type SharedInformerFactory interface { ForResource(resource schema.GroupVersionResource) (GenericInformer, error) WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool - Eventing() eventing.Interface + Sources() sources.Interface } -func (f *sharedInformerFactory) Eventing() eventing.Interface { - return eventing.New(f, f.namespace, f.tweakListOptions) +func (f *sharedInformerFactory) Sources() sources.Interface { + return sources.New(f, f.namespace, f.tweakListOptions) } diff --git a/pkg/client/informers/externalversions/generic.go b/pkg/client/informers/externalversions/generic.go index 6c22f720af9..8a1014ec955 100644 --- a/pkg/client/informers/externalversions/generic.go +++ b/pkg/client/informers/externalversions/generic.go @@ -21,7 +21,7 @@ package externalversions import ( "fmt" - v1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" + v1alpha1 "github.com/knative/eventing/pkg/apis/sources/v1alpha1" schema "k8s.io/apimachinery/pkg/runtime/schema" cache "k8s.io/client-go/tools/cache" ) @@ -52,17 +52,9 @@ func (f *genericInformer) Lister() cache.GenericLister { // TODO extend this to unknown resources with a client pool 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"): - 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 + // Group=sources.eventing.knative.dev, Version=v1alpha1 + case v1alpha1.SchemeGroupVersion.WithResource("cronjobsources"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Sources().V1alpha1().CronJobSources().Informer()}, nil } diff --git a/pkg/client/informers/externalversions/sources/interface.go b/pkg/client/informers/externalversions/sources/interface.go new file mode 100644 index 00000000000..654f1938531 --- /dev/null +++ b/pkg/client/informers/externalversions/sources/interface.go @@ -0,0 +1,46 @@ +/* +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 sources + +import ( + internalinterfaces "github.com/knative/eventing/pkg/client/informers/externalversions/internalinterfaces" + v1alpha1 "github.com/knative/eventing/pkg/client/informers/externalversions/sources/v1alpha1" +) + +// Interface provides access to each of this group's versions. +type Interface interface { + // V1alpha1 provides access to shared informers for resources in V1alpha1. + V1alpha1() v1alpha1.Interface +} + +type group struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// V1alpha1 returns a new v1alpha1.Interface. +func (g *group) V1alpha1() v1alpha1.Interface { + return v1alpha1.New(g.factory, g.namespace, g.tweakListOptions) +} diff --git a/pkg/client/informers/externalversions/sources/v1alpha1/cronjobsource.go b/pkg/client/informers/externalversions/sources/v1alpha1/cronjobsource.go new file mode 100644 index 00000000000..c05b7692e5a --- /dev/null +++ b/pkg/client/informers/externalversions/sources/v1alpha1/cronjobsource.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" + + sourcesv1alpha1 "github.com/knative/eventing/pkg/apis/sources/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/sources/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" +) + +// CronJobSourceInformer provides access to a shared informer and lister for +// CronJobSources. +type CronJobSourceInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1alpha1.CronJobSourceLister +} + +type cronJobSourceInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewCronJobSourceInformer constructs a new informer for CronJobSource 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 NewCronJobSourceInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredCronJobSourceInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredCronJobSourceInformer constructs a new informer for CronJobSource 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 NewFilteredCronJobSourceInformer(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.SourcesV1alpha1().CronJobSources(namespace).List(options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.SourcesV1alpha1().CronJobSources(namespace).Watch(options) + }, + }, + &sourcesv1alpha1.CronJobSource{}, + resyncPeriod, + indexers, + ) +} + +func (f *cronJobSourceInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredCronJobSourceInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *cronJobSourceInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&sourcesv1alpha1.CronJobSource{}, f.defaultInformer) +} + +func (f *cronJobSourceInformer) Lister() v1alpha1.CronJobSourceLister { + return v1alpha1.NewCronJobSourceLister(f.Informer().GetIndexer()) +} diff --git a/pkg/client/informers/externalversions/sources/v1alpha1/interface.go b/pkg/client/informers/externalversions/sources/v1alpha1/interface.go new file mode 100644 index 00000000000..cf621f01e7e --- /dev/null +++ b/pkg/client/informers/externalversions/sources/v1alpha1/interface.go @@ -0,0 +1,45 @@ +/* +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 ( + internalinterfaces "github.com/knative/eventing/pkg/client/informers/externalversions/internalinterfaces" +) + +// Interface provides access to all the informers in this group version. +type Interface interface { + // CronJobSources returns a CronJobSourceInformer. + CronJobSources() CronJobSourceInformer +} + +type version struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// CronJobSources returns a CronJobSourceInformer. +func (v *version) CronJobSources() CronJobSourceInformer { + return &cronJobSourceInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} diff --git a/pkg/client/listers/sources/v1alpha1/cronjobsource.go b/pkg/client/listers/sources/v1alpha1/cronjobsource.go new file mode 100644 index 00000000000..4c4d43bcfac --- /dev/null +++ b/pkg/client/listers/sources/v1alpha1/cronjobsource.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/sources/v1alpha1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" +) + +// CronJobSourceLister helps list CronJobSources. +type CronJobSourceLister interface { + // List lists all CronJobSources in the indexer. + List(selector labels.Selector) (ret []*v1alpha1.CronJobSource, err error) + // CronJobSources returns an object that can list and get CronJobSources. + CronJobSources(namespace string) CronJobSourceNamespaceLister + CronJobSourceListerExpansion +} + +// cronJobSourceLister implements the CronJobSourceLister interface. +type cronJobSourceLister struct { + indexer cache.Indexer +} + +// NewCronJobSourceLister returns a new CronJobSourceLister. +func NewCronJobSourceLister(indexer cache.Indexer) CronJobSourceLister { + return &cronJobSourceLister{indexer: indexer} +} + +// List lists all CronJobSources in the indexer. +func (s *cronJobSourceLister) List(selector labels.Selector) (ret []*v1alpha1.CronJobSource, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.CronJobSource)) + }) + return ret, err +} + +// CronJobSources returns an object that can list and get CronJobSources. +func (s *cronJobSourceLister) CronJobSources(namespace string) CronJobSourceNamespaceLister { + return cronJobSourceNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// CronJobSourceNamespaceLister helps list and get CronJobSources. +type CronJobSourceNamespaceLister interface { + // List lists all CronJobSources in the indexer for a given namespace. + List(selector labels.Selector) (ret []*v1alpha1.CronJobSource, err error) + // Get retrieves the CronJobSource from the indexer for a given namespace and name. + Get(name string) (*v1alpha1.CronJobSource, error) + CronJobSourceNamespaceListerExpansion +} + +// cronJobSourceNamespaceLister implements the CronJobSourceNamespaceLister +// interface. +type cronJobSourceNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all CronJobSources in the indexer for a given namespace. +func (s cronJobSourceNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.CronJobSource, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.CronJobSource)) + }) + return ret, err +} + +// Get retrieves the CronJobSource from the indexer for a given namespace and name. +func (s cronJobSourceNamespaceLister) Get(name string) (*v1alpha1.CronJobSource, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1alpha1.Resource("cronjobsource"), name) + } + return obj.(*v1alpha1.CronJobSource), nil +} diff --git a/pkg/client/listers/sources/v1alpha1/expansion_generated.go b/pkg/client/listers/sources/v1alpha1/expansion_generated.go new file mode 100644 index 00000000000..f9b1368c856 --- /dev/null +++ b/pkg/client/listers/sources/v1alpha1/expansion_generated.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. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha1 + +// CronJobSourceListerExpansion allows custom methods to be added to +// CronJobSourceLister. +type CronJobSourceListerExpansion interface{} + +// CronJobSourceNamespaceListerExpansion allows custom methods to be added to +// CronJobSourceNamespaceLister. +type CronJobSourceNamespaceListerExpansion interface{} From 43f7b01c9573c7a2047c0bbc0767de3638d235e2 Mon Sep 17 00:00:00 2001 From: Scott Nichols Date: Tue, 23 Apr 2019 09:07:07 -0700 Subject: [PATCH 02/25] stage this. --- Gopkg.lock | 38 +- pkg/adapter/cronjobevents/adapter.go | 117 ++++ pkg/adapter/cronjobevents/adapter_test.go | 208 ++++++ .../containersource/containersource.go | 253 +++++++ .../containersource/containersource_test.go | 642 ++++++++++++++++++ pkg/reconciler/containersource/doc.go | 18 + .../containersource/resources/arguments.go | 34 + .../containersource/resources/deployment.go | 115 ++++ .../resources/deployment_test.go | 292 ++++++++ .../knative/eventing-sources/AUTHORS | 6 + .../knative/eventing-sources/LICENSE | 201 ++++++ .../apis/sources/v1alpha1/aws_sqs_types.go | 154 +++++ .../sources/v1alpha1/containersource_types.go | 157 +++++ .../apis/sources/v1alpha1/cron_job_types.go | 164 +++++ .../pkg/apis/sources/v1alpha1/doc.go | 23 + .../sources/v1alpha1/githubsource_types.go | 195 ++++++ .../v1alpha1/kuberneteseventsource_types.go | 122 ++++ .../pkg/apis/sources/v1alpha1/register.go | 45 ++ .../sources/v1alpha1/zz_generated.deepcopy.go | 562 +++++++++++++++ .../pkg/controller/sdk/finalizers_accessor.go | 82 +++ .../pkg/controller/sdk/provider.go | 74 ++ .../pkg/controller/sdk/reconciler.go | 186 +++++ .../pkg/controller/sdk/status_accessor.go | 77 +++ .../pkg/controller/sinks/sinks.go | 61 ++ .../pkg/controller/testing/mock_client.go | 153 +++++ .../pkg/controller/testing/table.go | 275 ++++++++ .../pkg/kncloudevents/good_client.go | 28 + .../containersource/resources/arguments.go | 34 + .../containersource/resources/deployment.go | 115 ++++ .../test/test_images/k8sevents/kodata/LICENSE | 1 + .../k8sevents/kodata/VENDOR-LICENSE | 1 + vendor/github.com/robfig/cron/LICENSE | 21 + .../github.com/robfig/cron/constantdelay.go | 27 + vendor/github.com/robfig/cron/cron.go | 259 +++++++ vendor/github.com/robfig/cron/doc.go | 129 ++++ vendor/github.com/robfig/cron/parser.go | 380 +++++++++++ vendor/github.com/robfig/cron/spec.go | 158 +++++ .../controllerutil/controllerutil.go | 178 +++++ .../pkg/controller/controllerutil/doc.go | 20 + .../pkg/runtime/scheme/scheme.go | 56 ++ 40 files changed, 5660 insertions(+), 1 deletion(-) create mode 100644 pkg/adapter/cronjobevents/adapter.go create mode 100644 pkg/adapter/cronjobevents/adapter_test.go create mode 100644 pkg/reconciler/containersource/containersource.go create mode 100644 pkg/reconciler/containersource/containersource_test.go create mode 100644 pkg/reconciler/containersource/doc.go create mode 100644 pkg/reconciler/containersource/resources/arguments.go create mode 100644 pkg/reconciler/containersource/resources/deployment.go create mode 100644 pkg/reconciler/containersource/resources/deployment_test.go create mode 100644 vendor/github.com/knative/eventing-sources/AUTHORS create mode 100644 vendor/github.com/knative/eventing-sources/LICENSE create mode 100644 vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/aws_sqs_types.go create mode 100644 vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/containersource_types.go create mode 100644 vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/cron_job_types.go create mode 100644 vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/doc.go create mode 100644 vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/githubsource_types.go create mode 100644 vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/kuberneteseventsource_types.go create mode 100644 vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/register.go create mode 100644 vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/zz_generated.deepcopy.go create mode 100644 vendor/github.com/knative/eventing-sources/pkg/controller/sdk/finalizers_accessor.go create mode 100644 vendor/github.com/knative/eventing-sources/pkg/controller/sdk/provider.go create mode 100644 vendor/github.com/knative/eventing-sources/pkg/controller/sdk/reconciler.go create mode 100644 vendor/github.com/knative/eventing-sources/pkg/controller/sdk/status_accessor.go create mode 100644 vendor/github.com/knative/eventing-sources/pkg/controller/sinks/sinks.go create mode 100644 vendor/github.com/knative/eventing-sources/pkg/controller/testing/mock_client.go create mode 100644 vendor/github.com/knative/eventing-sources/pkg/controller/testing/table.go create mode 100644 vendor/github.com/knative/eventing-sources/pkg/kncloudevents/good_client.go create mode 100644 vendor/github.com/knative/eventing-sources/pkg/reconciler/containersource/resources/arguments.go create mode 100644 vendor/github.com/knative/eventing-sources/pkg/reconciler/containersource/resources/deployment.go create mode 120000 vendor/github.com/knative/eventing-sources/test/test_images/k8sevents/kodata/LICENSE create mode 120000 vendor/github.com/knative/eventing-sources/test/test_images/k8sevents/kodata/VENDOR-LICENSE create mode 100644 vendor/github.com/robfig/cron/LICENSE create mode 100644 vendor/github.com/robfig/cron/constantdelay.go create mode 100644 vendor/github.com/robfig/cron/cron.go create mode 100644 vendor/github.com/robfig/cron/doc.go create mode 100644 vendor/github.com/robfig/cron/parser.go create mode 100644 vendor/github.com/robfig/cron/spec.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/controller/controllerutil/controllerutil.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/controller/controllerutil/doc.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/runtime/scheme/scheme.go diff --git a/Gopkg.lock b/Gopkg.lock index 7d6b6d09c1b..85e814985d6 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -424,6 +424,21 @@ pruneopts = "NUT" revision = "f2b4162afba35581b6d4a50d3b8f34e33c144682" +[[projects]] + digest = "1:94171d9b3c7cfea54e726005e58044a2325ccf796ecf4bf025a3d20a1e145fba" + name = "github.com/knative/eventing-sources" + packages = [ + "pkg/apis/sources/v1alpha1", + "pkg/controller/sdk", + "pkg/controller/sinks", + "pkg/controller/testing", + "pkg/kncloudevents", + "pkg/reconciler/containersource/resources", + ] + pruneopts = "NUT" + revision = "32ce3778fa1bc46ed0b0ade16d5c57f343cafa4d" + version = "v0.5.0" + [[projects]] digest = "1:b657ec75371e8baf47023f7eb4f20d78e2a744f51ec824b40dd6cf74ad6fdaf4" name = "github.com/knative/pkg" @@ -676,6 +691,14 @@ pruneopts = "NUT" revision = "3113b8401b8a98917cde58f8bbd42a1b1c03b1fd" +[[projects]] + digest = "1:53c3320ee307f01fd24a88e396a8d2239cd8346d1a085320209319f2d33f59cc" + name = "github.com/robfig/cron" + packages = ["."] + pruneopts = "NUT" + revision = "b41be1df696709bb6395fe435af20370037c0b4c" + version = "v1.1" + [[projects]] digest = "1:d917313f309bda80d27274d53985bc65651f81a5b66b820749ac7f8ef061fd04" name = "github.com/sergi/go-diff" @@ -1313,7 +1336,7 @@ revision = "8a9b82f00b3a86eac24681da3f9fe6c34c01cea2" [[projects]] - digest = "1:a8495647d9f03401c36b801a0644207a434f76ed9d4fc4ea80c46700f0ccc575" + digest = "1:399953e7c3ac9253dcf1fe909b0a74f6d1c4e974decefd6f5d361cab06249ccc" name = "sigs.k8s.io/controller-runtime" packages = [ "pkg/cache", @@ -1323,6 +1346,7 @@ "pkg/client/config", "pkg/client/fake", "pkg/controller", + "pkg/controller/controllerutil", "pkg/event", "pkg/handler", "pkg/internal/controller", @@ -1337,6 +1361,7 @@ "pkg/recorder", "pkg/runtime/inject", "pkg/runtime/log", + "pkg/runtime/scheme", "pkg/runtime/signals", "pkg/source", "pkg/source/internal", @@ -1357,11 +1382,20 @@ "github.com/Shopify/sarama", "github.com/bsm/sarama-cluster", "github.com/cloudevents/sdk-go", + "github.com/cloudevents/sdk-go/pkg/cloudevents", + "github.com/cloudevents/sdk-go/pkg/cloudevents/client", "github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http", + "github.com/cloudevents/sdk-go/pkg/cloudevents/types", "github.com/fsnotify/fsnotify", "github.com/google/go-cmp/cmp", "github.com/google/go-cmp/cmp/cmpopts", "github.com/google/uuid", + "github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1", + "github.com/knative/eventing-sources/pkg/controller/sdk", + "github.com/knative/eventing-sources/pkg/controller/sinks", + "github.com/knative/eventing-sources/pkg/controller/testing", + "github.com/knative/eventing-sources/pkg/kncloudevents", + "github.com/knative/eventing-sources/pkg/reconciler/containersource/resources", "github.com/knative/pkg/apis", "github.com/knative/pkg/apis/duck", "github.com/knative/pkg/apis/duck/v1alpha1", @@ -1386,6 +1420,7 @@ "github.com/nats-io/go-nats-streaming", "github.com/nats-io/nats-streaming-server/server", "github.com/prometheus/client_golang/prometheus/promhttp", + "github.com/robfig/cron", "go.opencensus.io/exporter/prometheus", "go.opencensus.io/stats", "go.opencensus.io/stats/view", @@ -1447,6 +1482,7 @@ "sigs.k8s.io/controller-runtime/pkg/client/config", "sigs.k8s.io/controller-runtime/pkg/client/fake", "sigs.k8s.io/controller-runtime/pkg/controller", + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil", "sigs.k8s.io/controller-runtime/pkg/event", "sigs.k8s.io/controller-runtime/pkg/handler", "sigs.k8s.io/controller-runtime/pkg/manager", diff --git a/pkg/adapter/cronjobevents/adapter.go b/pkg/adapter/cronjobevents/adapter.go new file mode 100644 index 00000000000..fb87a8cb82f --- /dev/null +++ b/pkg/adapter/cronjobevents/adapter.go @@ -0,0 +1,117 @@ +/* +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 cronjobevents + +import ( + "context" + "encoding/json" + + "github.com/knative/eventing-sources/pkg/kncloudevents" + + "github.com/cloudevents/sdk-go/pkg/cloudevents" + "github.com/cloudevents/sdk-go/pkg/cloudevents/client" + "github.com/cloudevents/sdk-go/pkg/cloudevents/types" + + "github.com/robfig/cron" + + "github.com/knative/pkg/logging" + "go.uber.org/zap" +) + +const ( + eventType = "dev.knative.cronjob.event" +) + +// TODO: this should be a k8s cron. + +// Adapter implements the Cron Job adapter to trigger a Sink. +type Adapter struct { + // Schedule is a cron format string such as 0 * * * * or @hourly + Schedule string + + // Data is the data to be posted to the target. + Data string + + // SinkURI is the URI messages will be forwarded on to. + SinkURI string + + // client sends cloudevents. + client client.Client +} + +// Initialize cloudevent client +func (a *Adapter) initClient() error { + if a.client == nil { + var err error + if a.client, err = kncloudevents.NewDefaultClient(a.SinkURI); err != nil { + return err + } + } + return nil +} + +func (a *Adapter) Start(ctx context.Context, stopCh <-chan struct{}) error { + logger := logging.FromContext(ctx) + + sched, err := cron.ParseStandard(a.Schedule) + if err != nil { + logger.Error("Unparseable schedule: ", a.Schedule, zap.Error(err)) + return err + } + + if err = a.initClient(); err != nil { + logger.Error("Failed to create cloudevent client", zap.Error(err)) + return err + } + + c := cron.New() + c.Schedule(sched, cron.FuncJob(a.cronTick)) + c.Start() + <-stopCh + c.Stop() + logger.Info("Shutting down.") + return nil +} + +func (a *Adapter) cronTick() { + logger := logging.FromContext(context.TODO()) + + event := cloudevents.Event{ + Context: cloudevents.EventContextV02{ + Type: eventType, + Source: *types.ParseURLRef("/CronJob"), + }.AsV02(), + Data: message(a.Data), + } + if _, err := a.client.Send(context.TODO(), event); err != nil { + logger.Error("failed to send cloudevent", err) + } +} + +type Message struct { + Body string `json:"body"` +} + +func message(body string) interface{} { + // try to marshal the body into an interface. + var objmap map[string]*json.RawMessage + if err := json.Unmarshal([]byte(body), &objmap); err != nil { + //default to a wrapped message. + return Message{Body: body} + } + return objmap +} diff --git a/pkg/adapter/cronjobevents/adapter_test.go b/pkg/adapter/cronjobevents/adapter_test.go new file mode 100644 index 00000000000..8416664f7b9 --- /dev/null +++ b/pkg/adapter/cronjobevents/adapter_test.go @@ -0,0 +1,208 @@ +/* +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 cronjobevents + +import ( + "context" + "encoding/json" + "io/ioutil" + "log" + "net/http" + "net/http/httptest" + "testing" + + "github.com/google/go-cmp/cmp" +) + +func TestStart_ServeHTTP(t *testing.T) { + testCases := map[string]struct { + schedule string + sink func(http.ResponseWriter, *http.Request) + reqBody string + error bool + }{ + "happy": { + schedule: "* * * * *", // every minute + sink: sinkAccepted, + reqBody: `{"body":"data"}`, + }, + "rejected": { + schedule: "* * * * *", // every minute + sink: sinkRejected, + reqBody: `{"body":"data"}`, + error: true, + }, + } + for n, tc := range testCases { + t.Run(n, func(t *testing.T) { + h := &fakeHandler{ + handler: tc.sink, + } + sinkServer := httptest.NewServer(h) + defer sinkServer.Close() + + a := &Adapter{ + Schedule: tc.schedule, + Data: "data", + SinkURI: sinkServer.URL, + } + + if err := a.initClient(); err != nil { + t.Errorf("failed to create cloudevent client, %v", err) + } + + stop := make(chan struct{}) + go func() { + if err := a.Start(context.TODO(), stop); err != nil { + if tc.error { + // skip + } else { + t.Errorf("failed to start, %v", err) + } + } + }() + + a.cronTick() // force a tick. + + if tc.reqBody != string(h.body) { + t.Errorf("expected request body %q, but got %q", tc.reqBody, h.body) + } + log.Print("test done") + }) + } +} + +func TestStartBadCron(t *testing.T) { + schedule := "bad" + + a := &Adapter{ + Schedule: schedule, + } + + stop := make(chan struct{}) + if err := a.Start(context.TODO(), stop); err == nil { + + t.Errorf("failed to fail, %v", err) + + } +} + +func TestPostMessage_ServeHTTP(t *testing.T) { + testCases := map[string]struct { + sink func(http.ResponseWriter, *http.Request) + reqBody string + error bool + }{ + "happy": { + sink: sinkAccepted, + reqBody: `{"body":"data"}`, + }, + "rejected": { + sink: sinkRejected, + reqBody: `{"body":"data"}`, + error: true, + }, + } + for n, tc := range testCases { + t.Run(n, func(t *testing.T) { + h := &fakeHandler{ + handler: tc.sink, + } + sinkServer := httptest.NewServer(h) + defer sinkServer.Close() + + a := &Adapter{ + Data: "data", + SinkURI: sinkServer.URL, + } + + if err := a.initClient(); err != nil { + t.Errorf("failed to create cloudevent client, %v", err) + } + + a.cronTick() + + if tc.reqBody != string(h.body) { + t.Errorf("expected request body %q, but got %q", tc.reqBody, h.body) + } + }) + } +} + +func TestMessage(t *testing.T) { + testCases := map[string]struct { + body string + want string + }{ + "json simple": { + body: `{"message": "Hello world!"}`, + want: `{"message":"Hello world!"}`, + }, + "json complex": { + body: `{"message": "Hello world!","extra":{"a":"sub", "b":[1,2,3]}}`, + want: `{"extra":{"a":"sub","b":[1,2,3]},"message":"Hello world!"}`, + }, + "string": { + body: "Hello, World!", + want: `{"body":"Hello, World!"}`, + }, + } + for n, tc := range testCases { + t.Run(n, func(t *testing.T) { + + m := message(tc.body) + + j, err := json.Marshal(m) + if err != nil { + t.Errorf("failed to marshel message: %v", err) + } + + got := string(j) + if diff := cmp.Diff(tc.want, got); diff != "" { + t.Errorf("%s: (-want, +got) = %v", n, diff) + } + }) + } +} + +type fakeHandler struct { + body []byte + ran int + handler func(http.ResponseWriter, *http.Request) +} + +func (h *fakeHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + body, err := ioutil.ReadAll(r.Body) + if err != nil { + http.Error(w, "can not read body", http.StatusBadRequest) + return + } + h.body = body + + defer r.Body.Close() + h.handler(w, r) + + h.ran++ +} + +func sinkAccepted(writer http.ResponseWriter, req *http.Request) { + writer.WriteHeader(http.StatusOK) +} + +func sinkRejected(writer http.ResponseWriter, _ *http.Request) { + writer.WriteHeader(http.StatusRequestTimeout) +} diff --git a/pkg/reconciler/containersource/containersource.go b/pkg/reconciler/containersource/containersource.go new file mode 100644 index 00000000000..87cd1a8b705 --- /dev/null +++ b/pkg/reconciler/containersource/containersource.go @@ -0,0 +1,253 @@ +/* +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 containersource + +import ( + "context" + "fmt" + "strings" + + "github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1" + "github.com/knative/eventing-sources/pkg/controller/sdk" + "github.com/knative/eventing-sources/pkg/controller/sinks" + "github.com/knative/eventing-sources/pkg/reconciler/containersource/resources" + "github.com/knative/pkg/logging" + "go.uber.org/zap" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/equality" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/api/meta" + 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/client-go/tools/record" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "sigs.k8s.io/controller-runtime/pkg/manager" +) + +const ( + // controllerAgentName is the string used by this controller to identify + // itself when creating events. + controllerAgentName = "container-source-controller" +) + +// Add creates a new ContainerSource Controller and adds it to the Manager with +// default RBAC. The Manager will set fields on the Controller and Start it when +// the Manager is Started. +func Add(mgr manager.Manager, logger *zap.SugaredLogger) error { + p := &sdk.Provider{ + AgentName: controllerAgentName, + Parent: &v1alpha1.ContainerSource{}, + Owns: []runtime.Object{&appsv1.Deployment{}}, + Reconciler: &reconciler{ + recorder: mgr.GetRecorder(controllerAgentName), + scheme: mgr.GetScheme(), + }, + } + + return p.Add(mgr, logger) +} + +type reconciler struct { + client client.Client + scheme *runtime.Scheme + recorder record.EventRecorder +} + +// Reconcile compares the actual state with the desired, and attempts to +// converge the two. +func (r *reconciler) Reconcile(ctx context.Context, object runtime.Object) error { + logger := logging.FromContext(ctx) + + source, ok := object.(*v1alpha1.ContainerSource) + if !ok { + logger.Errorf("could not find container source %v\n", object) + return nil + } + + // See if the source has been deleted + accessor, err := meta.Accessor(source) + if err != nil { + logger.Warnf("Failed to get metadata accessor: %s", zap.Error(err)) + return err + } + // No need to reconcile if the source has been marked for deletion. + deletionTimestamp := accessor.GetDeletionTimestamp() + if deletionTimestamp != nil { + return nil + } + + source.Status.InitializeConditions() + + annotations := make(map[string]string) + // Then wire through any annotations / labels from the Source + if source.ObjectMeta.Annotations != nil { + for k, v := range source.ObjectMeta.Annotations { + annotations[k] = v + } + } + labels := make(map[string]string) + if source.ObjectMeta.Labels != nil { + for k, v := range source.ObjectMeta.Labels { + labels[k] = v + } + } + + args := &resources.ContainerArguments{ + Name: source.Name, + Namespace: source.Namespace, + Image: source.Spec.Image, + Args: source.Spec.Args, + Env: source.Spec.Env, + ServiceAccountName: source.Spec.ServiceAccountName, + Annotations: annotations, + Labels: labels, + } + + err = r.setSinkURIArg(ctx, source, args) + if err != nil { + return err + } + + deploy, err := r.getDeployment(ctx, source) + if err != nil { + if errors.IsNotFound(err) { + deploy, err = r.createDeployment(ctx, source, nil, args) + if err != nil { + r.recorder.Eventf(source, corev1.EventTypeNormal, "DeploymentBlocked", "waiting for %v", err) + return err + } + r.recorder.Eventf(source, corev1.EventTypeNormal, "Deployed", "Created deployment %q", deploy.Name) + source.Status.MarkDeploying("Deploying", "Created deployment %s", deploy.Name) + // Since the Deployment has just been created, there's nothing more + // to do until it gets a status. This ContainerSource will be reconciled + // again when the Deployment is updated. + return nil + } + return err + } + + // Update Deployment spec if it's changed + expected := resources.MakeDeployment(nil, args) + // Since the Deployment spec has fields defaulted by the webhook, it won't + // be equal to expected. Use DeepDerivative to compare only the fields that + // are set in expected. + if !equality.Semantic.DeepDerivative(expected.Spec, deploy.Spec) { + deploy.Spec = expected.Spec + err := r.client.Update(ctx, deploy) + // if no error, update the status. + if err == nil { + source.Status.MarkDeploying("DeployUpdated", "Updated deployment %s", deploy.Name) + } else { + source.Status.MarkDeploying("DeployNeedsUpdate", "Attempting to update deployment %s", deploy.Name) + r.recorder.Eventf(source, corev1.EventTypeWarning, "DeployNeedsUpdate", "Failed to update deployment %q", deploy.Name) + } + // Return after this update or error and reconcile again + return err + } + + // Update source status + if deploy.Status.ReadyReplicas > 0 { + source.Status.MarkDeployed() + } + + return nil +} + +func (r *reconciler) setSinkURIArg(ctx context.Context, source *v1alpha1.ContainerSource, args *resources.ContainerArguments) error { + if uri, ok := sinkArg(source); ok { + args.SinkInArgs = true + source.Status.MarkSink(uri) + return nil + } + + if source.Spec.Sink == nil { + source.Status.MarkNoSink("Missing", "") + return fmt.Errorf("Sink missing from spec") + } + + uri, err := sinks.GetSinkURI(ctx, r.client, source.Spec.Sink, source.Namespace) + if err != nil { + source.Status.MarkNoSink("NotFound", "") + return err + } + source.Status.MarkSink(uri) + args.Sink = uri + + return nil +} + +func sinkArg(source *v1alpha1.ContainerSource) (string, bool) { + for _, a := range source.Spec.Args { + if strings.HasPrefix(a, "--sink=") { + return strings.Replace(a, "--sink=", "", -1), true + } + } + return "", false +} + +func (r *reconciler) getDeployment(ctx context.Context, source *v1alpha1.ContainerSource) (*appsv1.Deployment, error) { + logger := logging.FromContext(ctx) + + list := &appsv1.DeploymentList{} + err := r.client.List( + ctx, + &client.ListOptions{ + Namespace: source.Namespace, + LabelSelector: labels.Everything(), + // 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: appsv1.SchemeGroupVersion.String(), + Kind: "Deployment", + }, + }, + }, + list) + if err != nil { + logger.Errorf("Unable to list deployments: %v", zap.Error(err)) + return nil, err + } + for _, c := range list.Items { + if metav1.IsControlledBy(&c, source) { + return &c, nil + } + } + return nil, errors.NewNotFound(schema.GroupResource{}, "") +} + +func (r *reconciler) createDeployment(ctx context.Context, source *v1alpha1.ContainerSource, org *appsv1.Deployment, args *resources.ContainerArguments) (*appsv1.Deployment, error) { + deployment := resources.MakeDeployment(org, args) + + if err := controllerutil.SetControllerReference(source, deployment, r.scheme); err != nil { + return nil, err + } + + if err := r.client.Create(ctx, deployment); err != nil { + return nil, err + } + return deployment, nil +} + +func (r *reconciler) InjectClient(c client.Client) error { + r.client = c + return nil +} diff --git a/pkg/reconciler/containersource/containersource_test.go b/pkg/reconciler/containersource/containersource_test.go new file mode 100644 index 00000000000..958db6b3af3 --- /dev/null +++ b/pkg/reconciler/containersource/containersource_test.go @@ -0,0 +1,642 @@ +/* +Copyright 2018 The Knative Authors + +Licensed under the Apache License, Veroute.on 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT 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 containersource + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "testing" + + "github.com/google/go-cmp/cmp" + sourcesv1alpha1 "github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1" + controllertesting "github.com/knative/eventing-sources/pkg/controller/testing" + "github.com/knative/eventing-sources/pkg/reconciler/containersource/resources" + duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" + appsv1 "k8s.io/api/apps/v1" + 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/client-go/kubernetes/scheme" + "k8s.io/client-go/tools/record" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var ( + trueVal = true + targetURI = "http://addressable.sink.svc.cluster.local/" +) + +const ( + image = "github.com/knative/test/image" + containerSourceName = "testcontainersource" + testNS = "testnamespace" + containerSourceUID = "2a2208d1-ce67-11e8-b3a3-42010a8a00af" + deployGeneratedName = "" //sad trombone + + addressableDNS = "addressable.sink.svc.cluster.local" + + addressableName = "testsink" + addressableKind = "Sink" + addressableAPIVersion = "duck.knative.dev/v1alpha1" + + unaddressableName = "testunaddressable" + unaddressableKind = "KResource" + unaddressableAPIVersion = "duck.knative.dev/v1alpha1" + + sinkServiceName = "testsinkservice" + sinkServiceKind = "Service" + sinkServiceAPIVersion = "v1" +) + +func init() { + // Add types to scheme + sourcesv1alpha1.SchemeBuilder.AddToScheme(scheme.Scheme) + duckv1alpha1.AddToScheme(scheme.Scheme) +} + +var testCases = []controllertesting.TestCase{ + { + Name: "non existent key", + Reconciles: &sourcesv1alpha1.ContainerSource{}, + ReconcileKey: "non-existent-test-ns/non-existent-test-key", + WantErr: false, + }, { + Name: "valid containersource, but sink does not exist", + Reconciles: &sourcesv1alpha1.ContainerSource{}, + InitialState: []runtime.Object{ + getContainerSource(), + }, + ReconcileKey: fmt.Sprintf("%s/%s", testNS, containerSourceName), + WantErrMsg: `sinks.duck.knative.dev "testsink" not found`, + }, { + Name: "valid containersource, but sink is not addressable", + Reconciles: &sourcesv1alpha1.ContainerSource{}, + InitialState: []runtime.Object{ + getContainerSourceUnaddressable(), + getAddressableNoStatus(), + }, + ReconcileKey: fmt.Sprintf("%s/%s", testNS, containerSourceName), + Scheme: scheme.Scheme, + WantErrMsg: `sink "testnamespace/testunaddressable" (duck.knative.dev/v1alpha1, Kind=KResource) does not contain address`, + }, { + Name: "valid containersource, sink is addressable", + Reconciles: &sourcesv1alpha1.ContainerSource{}, + InitialState: []runtime.Object{ + getContainerSource(), + getAddressable(), + }, + ReconcileKey: fmt.Sprintf("%s/%s", testNS, containerSourceName), + Scheme: scheme.Scheme, + WantPresent: []runtime.Object{ + func() runtime.Object { + s := getContainerSource() + s.Status.InitializeConditions() + s.Status.MarkDeploying("Deploying", "Created deployment %s", deployGeneratedName) + s.Status.MarkSink(targetURI) + return s + }(), + }, + IgnoreTimes: true, + }, { + Name: "valid containersource, sink is addressable, fields filled in", + Reconciles: &sourcesv1alpha1.ContainerSource{}, + InitialState: []runtime.Object{ + getContainerSourceFilledIn(), + getAddressable(), + }, + ReconcileKey: fmt.Sprintf("%s/%s", testNS, containerSourceName), + Scheme: scheme.Scheme, + WantPresent: []runtime.Object{ + getDeployment(getContainerSourceFilledIn()), + }, + IgnoreTimes: true, + }, { + Name: "valid containersource, sink is Addressable but sink is nil", + Reconciles: &sourcesv1alpha1.ContainerSource{}, + InitialState: []runtime.Object{ + getContainerSource(), + getAddressableNilAddress(), + }, + ReconcileKey: fmt.Sprintf("%s/%s", testNS, containerSourceName), + Scheme: scheme.Scheme, + WantPresent: []runtime.Object{ + func() runtime.Object { + s := getContainerSource() + s.Status.InitializeConditions() + s.Status.MarkNoSink("NotFound", "") + return s + }(), + }, + IgnoreTimes: true, + WantErrMsg: `sink "testnamespace/testsink" (duck.knative.dev/v1alpha1, Kind=Sink) does not contain address`, + }, { + Name: "invalid containersource, sink is nil", + Reconciles: &sourcesv1alpha1.ContainerSource{}, + InitialState: []runtime.Object{ + func() runtime.Object { + s := getContainerSource() + s.Spec.Sink = nil + return s + }(), + }, + ReconcileKey: fmt.Sprintf("%s/%s", testNS, containerSourceName), + Scheme: scheme.Scheme, + WantPresent: []runtime.Object{ + func() runtime.Object { + s := getContainerSource() + s.Spec.Sink = nil + s.Status.InitializeConditions() + s.Status.MarkNoSink("Missing", "") + return s + }(), + }, + IgnoreTimes: true, + WantErrMsg: `Sink missing from spec`, + }, { + Name: "valid containersource, sink is provided", + Reconciles: &sourcesv1alpha1.ContainerSource{}, + InitialState: []runtime.Object{ + func() runtime.Object { + s := getContainerSource() + s.Spec.Sink = nil + s.Spec.Args = append(s.Spec.Args, fmt.Sprintf("--sink=%s", targetURI)) + return s + }(), + }, + ReconcileKey: fmt.Sprintf("%s/%s", testNS, containerSourceName), + Scheme: scheme.Scheme, + WantPresent: []runtime.Object{ + func() runtime.Object { + s := getContainerSource() + s.Spec.Sink = nil + s.Spec.Args = append(s.Spec.Args, fmt.Sprintf("--sink=%s", targetURI)) + s.Status.InitializeConditions() + s.Status.MarkDeploying("Deploying", "Created deployment %s", deployGeneratedName) + s.Status.MarkSink(targetURI) + return s + }(), + }, + IgnoreTimes: true, + }, { + Name: "valid containersource, labels and annotations given", + Reconciles: &sourcesv1alpha1.ContainerSource{}, + InitialState: []runtime.Object{ + func() runtime.Object { + s := getContainerSource() + s.Spec.Sink = nil + s.Spec.Args = append(s.Spec.Args, fmt.Sprintf("--sink=%s", targetURI)) + s.ObjectMeta.Annotations = map[string]string{"annotation": "solid"} + s.ObjectMeta.Labels = map[string]string{"label": "soliderer"} + return s + }(), + }, + ReconcileKey: fmt.Sprintf("%s/%s", testNS, containerSourceName), + Scheme: scheme.Scheme, + WantPresent: []runtime.Object{ + func() runtime.Object { + s := getContainerSource() + s.Spec.Sink = nil + s.Spec.Args = append(s.Spec.Args, fmt.Sprintf("--sink=%s", targetURI)) + s.Status.InitializeConditions() + s.Status.MarkDeploying("Deploying", "Created deployment %s", deployGeneratedName) + s.Status.MarkSink(targetURI) + s.ObjectMeta.Annotations = map[string]string{"annotation": "solid"} + s.ObjectMeta.Labels = map[string]string{"label": "soliderer"} + return s + }(), + }, + IgnoreTimes: true, + }, { + Name: "valid containersource, sink, and deployment", + Reconciles: &sourcesv1alpha1.ContainerSource{}, + InitialState: []runtime.Object{ + func() runtime.Object { + s := getContainerSource() + s.UID = containerSourceUID + return s + }(), + func() runtime.Object { + // TODO(n3wscott): this is very strange, I was not able to get + // the fake client to return the resources.MakeDeployment version + // back in the list call. I might have missed setting some special + // metadata? Converting an unstructured and setting the fields + // I care about did work. + u := &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "namespace": testNS, + "name": containerSourceName + "-abc", + }, + }, + } + u.SetOwnerReferences(getOwnerReferences()) + + d := &appsv1.Deployment{} + d.Status.ReadyReplicas = 1 + j, _ := u.MarshalJSON() + json.Unmarshal(j, d) + + d1 := resources.MakeDeployment(nil, &resources.ContainerArguments{ + Name: containerSourceName, + Sink: "http://" + addressableDNS + "/", + Image: image, + }) + d.Spec = d1.Spec + return d + }(), + getAddressable(), + }, + ReconcileKey: fmt.Sprintf("%s/%s", testNS, containerSourceName), + Scheme: scheme.Scheme, + WantPresent: []runtime.Object{ + func() runtime.Object { + s := getContainerSource() + s.UID = containerSourceUID + s.Status.InitializeConditions() + s.Status.MarkDeployed() + s.Status.MarkSink(targetURI) + return s + }(), + }, + IgnoreTimes: true, + }, { + Name: "valid containersource, sink, but deployment needs update", + Reconciles: &sourcesv1alpha1.ContainerSource{}, + InitialState: []runtime.Object{ + func() runtime.Object { + s := getContainerSource() + s.UID = containerSourceUID + return s + }(), + func() runtime.Object { + // TODO(n3wscott): this is very strange, I was not able to get + // the fake client to return the resources.MakeDeployment version + // back in the list call. I might have missed setting some special + // metadata? Converting an unstructured and setting the fields + // I care about did work. + u := &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "namespace": testNS, + "name": containerSourceName + "-abc", + }, + }, + } + u.SetOwnerReferences(getOwnerReferences()) + + d := &appsv1.Deployment{} + d.Status.ReadyReplicas = 1 + j, _ := u.MarshalJSON() + json.Unmarshal(j, d) + + d1 := resources.MakeDeployment(nil, &resources.ContainerArguments{ + Name: containerSourceName, + Sink: "http://old-" + addressableDNS + "/", + Image: image, + }) + d.Spec = d1.Spec + return d + }(), + getAddressable(), + }, + ReconcileKey: fmt.Sprintf("%s/%s", testNS, containerSourceName), + Scheme: scheme.Scheme, + WantPresent: []runtime.Object{ + func() runtime.Object { + s := getContainerSource() + s.UID = containerSourceUID + s.Status.InitializeConditions() + s.Status.MarkDeploying("DeployUpdated", "Updated deployment %s", containerSourceName+"-abc") + s.Status.MarkSink(targetURI) + return s + }(), + }, + IgnoreTimes: true, + }, { + Name: "Error for create deployment", + Reconciles: &sourcesv1alpha1.ContainerSource{}, + InitialState: []runtime.Object{ + func() runtime.Object { + s := getContainerSource() + s.UID = containerSourceUID + return s + }(), + getAddressable(), + }, + ReconcileKey: fmt.Sprintf("%s/%s", testNS, containerSourceName), + Scheme: scheme.Scheme, + Mocks: controllertesting.Mocks{ + MockCreates: []controllertesting.MockCreate{ + func(_ client.Client, _ context.Context, _ runtime.Object) (controllertesting.MockHandled, error) { + return controllertesting.Handled, errors.New("force an error into client create") + }, + }, + }, + IgnoreTimes: true, + WantErrMsg: `force an error into client create`, + }, { + Name: "Error for get source, other than not found", + Reconciles: &sourcesv1alpha1.ContainerSource{}, + InitialState: []runtime.Object{ + func() runtime.Object { + s := getContainerSource() + s.UID = containerSourceUID + return s + }(), + getAddressable(), + }, + ReconcileKey: fmt.Sprintf("%s/%s", testNS, containerSourceName), + Scheme: scheme.Scheme, + Mocks: controllertesting.Mocks{ + MockLists: []controllertesting.MockList{ + func(_ client.Client, _ context.Context, _ *client.ListOptions, _ runtime.Object) (controllertesting.MockHandled, error) { + return controllertesting.Handled, errors.New("force an error into client list") + }, + }, + }, + IgnoreTimes: true, + WantErrMsg: `force an error into client list`, + }, + /* TODO: support k8s service { + Name: "valid containersource, sink is a k8s service", + Reconciles: &sourcesv1alpha1.ContainerSource{}, + InitialState: []runtime.Object{ + getContainerSourceSinkService(), + }, + ReconcileKey: fmt.Sprintf("%s/%s", testNS, containerSourceName), + Scheme: scheme.Scheme, + Objects: []runtime.Object{ + // addressable + &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": sinkServiceAPIVersion, + "kind": sinkServiceKind, + "metadata": map[string]interface{}{ + "namespace": testNS, + "name": sinkServiceName, + }, + }}, + }, + },*/ +} + +func TestAllCases(t *testing.T) { + recorder := record.NewBroadcaster().NewRecorder(scheme.Scheme, corev1.EventSource{Component: controllerAgentName}) + + for _, tc := range testCases { + c := tc.GetClient() + + r := &reconciler{ + scheme: tc.Scheme, + recorder: recorder, + } + r.InjectClient(c) + t.Run(tc.Name, tc.Runner(t, r, c)) + } +} + +func getContainerSource() *sourcesv1alpha1.ContainerSource { + obj := &sourcesv1alpha1.ContainerSource{ + TypeMeta: containerSourceType(), + ObjectMeta: om(testNS, containerSourceName), + Spec: sourcesv1alpha1.ContainerSourceSpec{ + Image: image, + Args: []string(nil), + Sink: &corev1.ObjectReference{ + Name: addressableName, + Kind: addressableKind, + APIVersion: addressableAPIVersion, + }, + }, + } + // selflink is not filled in when we create the object, so clear it + obj.ObjectMeta.SelfLink = "" + return obj +} + +func getContainerSourceFilledIn() *sourcesv1alpha1.ContainerSource { + obj := getContainerSource() + obj.ObjectMeta.UID = containerSourceUID + obj.Spec.Args = []string{"--foo", "bar"} + obj.Spec.Env = []corev1.EnvVar{{Name: "FOO", Value: "bar"}} + obj.Spec.ServiceAccountName = "foo" + return obj +} + +func getContainerSourceSinkService() *sourcesv1alpha1.ContainerSource { + obj := &sourcesv1alpha1.ContainerSource{ + TypeMeta: containerSourceType(), + ObjectMeta: om(testNS, containerSourceName), + Spec: sourcesv1alpha1.ContainerSourceSpec{ + Image: image, + Args: []string(nil), + Sink: &corev1.ObjectReference{ + Name: sinkServiceName, + Kind: sinkServiceKind, + APIVersion: sinkServiceAPIVersion, + }, + }, + } + // selflink is not filled in when we create the object, so clear it + obj.ObjectMeta.SelfLink = "" + return obj +} + +func getContainerSourceUnaddressable() *sourcesv1alpha1.ContainerSource { + obj := &sourcesv1alpha1.ContainerSource{ + TypeMeta: containerSourceType(), + ObjectMeta: om(testNS, containerSourceName), + Spec: sourcesv1alpha1.ContainerSourceSpec{ + Image: image, + Args: []string{}, + Sink: &corev1.ObjectReference{ + Name: unaddressableName, + Kind: unaddressableKind, + APIVersion: unaddressableAPIVersion, + }, + }, + } + // selflink is not filled in when we create the object, so clear it + obj.ObjectMeta.SelfLink = "" + return obj +} + +func getAddressable() *unstructured.Unstructured { + return &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": addressableAPIVersion, + "kind": addressableKind, + "metadata": map[string]interface{}{ + "namespace": testNS, + "name": addressableName, + }, + "status": map[string]interface{}{ + "address": map[string]interface{}{ + "hostname": addressableDNS, + }, + }, + }, + } +} + +func getAddressableNoStatus() *unstructured.Unstructured { + return &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": unaddressableAPIVersion, + "kind": unaddressableKind, + "metadata": map[string]interface{}{ + "namespace": testNS, + "name": unaddressableName, + }, + }, + } +} + +func getAddressableNilAddress() *unstructured.Unstructured { + return &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": addressableAPIVersion, + "kind": addressableKind, + "metadata": map[string]interface{}{ + "namespace": testNS, + "name": addressableName, + }, + "status": map[string]interface{}{ + "address": map[string]interface{}(nil), + }, + }, + } +} + +func getDeployment(source *sourcesv1alpha1.ContainerSource) *appsv1.Deployment { + addressableURI := fmt.Sprintf("http://%s/", addressableDNS) + args := append(source.Spec.Args, fmt.Sprintf("--sink=%s", addressableURI)) + env := append(source.Spec.Env, corev1.EnvVar{Name: "SINK", Value: addressableURI}) + return &appsv1.Deployment{ + TypeMeta: deploymentType(), + ObjectMeta: metav1.ObjectMeta{ + GenerateName: fmt.Sprintf("%s-", source.Name), + Namespace: source.Namespace, + OwnerReferences: getOwnerReferences(), + }, + Spec: appsv1.DeploymentSpec{ + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "eventing.knative.dev/source": source.Name, + }, + }, + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + "sidecar.istio.io/inject": "true", + }, + Labels: map[string]string{ + "eventing.knative.dev/source": source.Name, + }, + }, + Spec: corev1.PodSpec{ + Containers: []corev1.Container{{ + Name: "source", + Image: source.Spec.Image, + Args: args, + Env: env, + ImagePullPolicy: corev1.PullIfNotPresent, + }}, + ServiceAccountName: source.Spec.ServiceAccountName, + }, + }, + }, + } +} + +func containerSourceType() metav1.TypeMeta { + return metav1.TypeMeta{ + APIVersion: sourcesv1alpha1.SchemeGroupVersion.String(), + Kind: "ContainerSource", + } +} + +func deploymentType() metav1.TypeMeta { + return metav1.TypeMeta{ + APIVersion: appsv1.SchemeGroupVersion.String(), + Kind: "Deployment", + } +} + +func om(namespace, name string) metav1.ObjectMeta { + return metav1.ObjectMeta{ + Namespace: namespace, + Name: name, + SelfLink: fmt.Sprintf("/apis/eventing/sources/v1alpha1/namespaces/%s/object/%s", namespace, name), + } +} + +func getOwnerReferences() []metav1.OwnerReference { + return []metav1.OwnerReference{{ + APIVersion: sourcesv1alpha1.SchemeGroupVersion.String(), + Kind: "ContainerSource", + Name: containerSourceName, + Controller: &trueVal, + BlockOwnerDeletion: &trueVal, + UID: containerSourceUID, + }} +} + +// Direct Unit tests. + +func TestObjectNotContainerSource(t *testing.T) { + r := reconciler{} + obj := &corev1.ObjectReference{ + Name: unaddressableName, + Kind: unaddressableKind, + APIVersion: unaddressableAPIVersion, + } + + got := obj.DeepCopy() + gotErr := r.Reconcile(context.TODO(), got) + var want runtime.Object = obj + if diff := cmp.Diff(want, got); diff != "" { + t.Errorf("unexpected returned object (-want, +got) = %v", diff) + } + if gotErr != nil { + t.Errorf("unexpected returned error %v", gotErr) + } +} + +func TestObjectHasDeleteTimestamp(t *testing.T) { + r := reconciler{} + obj := getContainerSource() + + now := metav1.Now() + obj.DeletionTimestamp = &now + got := obj.DeepCopy() + gotErr := r.Reconcile(context.TODO(), got) + var want runtime.Object = obj + if diff := cmp.Diff(want, got); diff != "" { + t.Errorf("unexpected returned object (-want, +got) = %v", diff) + } + if gotErr != nil { + t.Errorf("unexpected returned error %v", gotErr) + } +} diff --git a/pkg/reconciler/containersource/doc.go b/pkg/reconciler/containersource/doc.go new file mode 100644 index 00000000000..d83e1353fc0 --- /dev/null +++ b/pkg/reconciler/containersource/doc.go @@ -0,0 +1,18 @@ +/* +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 containersource implements the ContainerSource controller. +package containersource diff --git a/pkg/reconciler/containersource/resources/arguments.go b/pkg/reconciler/containersource/resources/arguments.go new file mode 100644 index 00000000000..9eb2884f4f7 --- /dev/null +++ b/pkg/reconciler/containersource/resources/arguments.go @@ -0,0 +1,34 @@ +/* +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 ( + corev1 "k8s.io/api/core/v1" +) + +type ContainerArguments struct { + Name string + Namespace string + Image string + Args []string + Env []corev1.EnvVar + ServiceAccountName string + SinkInArgs bool + Sink string + Annotations map[string]string + Labels map[string]string +} diff --git a/pkg/reconciler/containersource/resources/deployment.go b/pkg/reconciler/containersource/resources/deployment.go new file mode 100644 index 00000000000..2e253dc3531 --- /dev/null +++ b/pkg/reconciler/containersource/resources/deployment.go @@ -0,0 +1,115 @@ +/* +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" + "strings" + + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +const sourceLabelKey = "eventing.knative.dev/source" + +func MakeDeployment(org *appsv1.Deployment, args *ContainerArguments) *appsv1.Deployment { + + containerArgs := []string(nil) + if args != nil { + containerArgs = args.Args + } + // if sink is already in the provided args.Args, don't attempt to add + if !args.SinkInArgs { + remote := fmt.Sprintf("--sink=%s", args.Sink) + containerArgs = append(containerArgs, remote) + } + + env := append(args.Env, corev1.EnvVar{Name: "SINK", Value: sinkArg(args)}) + + deploy := &appsv1.Deployment{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "apps/v1", + Kind: "Deployment", + }, + ObjectMeta: metav1.ObjectMeta{ + GenerateName: args.Name + "-", + Namespace: args.Namespace, + }, + Spec: appsv1.DeploymentSpec{ + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + sourceLabelKey: args.Name, + }, + }, + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + "sidecar.istio.io/inject": "true", + }, + Labels: map[string]string{ + sourceLabelKey: args.Name, + }, + }, + Spec: corev1.PodSpec{ + ServiceAccountName: args.ServiceAccountName, + Containers: []corev1.Container{ + { + Name: "source", + Image: args.Image, + Args: containerArgs, + Env: env, + ImagePullPolicy: corev1.PullIfNotPresent, + }, + }, + }, + }, + }, + } + + // Then wire through any annotations from the source. Not a bug by allowing + // the container to override Istio injection. + if args.Annotations != nil { + for k, v := range args.Annotations { + deploy.Spec.Template.ObjectMeta.Annotations[k] = v + } + } + + // Then wire through any labels from the source. Do not allow to override + // our source name. This seems like it would be way errorprone by allowing + // the matchlabels then to not match, or we'd have to force them to match, etc. + // just don't allow it. + if args.Labels != nil { + for k, v := range args.Labels { + if k != sourceLabelKey { + deploy.Spec.Template.ObjectMeta.Labels[k] = v + } + } + } + return deploy +} + +func sinkArg(args *ContainerArguments) string { + if args.SinkInArgs { + for _, a := range args.Args { + if strings.HasPrefix(a, "--sink=") { + return strings.Replace(a, "--sink=", "", -1) + } + } + } + return args.Sink +} diff --git a/pkg/reconciler/containersource/resources/deployment_test.go b/pkg/reconciler/containersource/resources/deployment_test.go new file mode 100644 index 00000000000..db01e14a23a --- /dev/null +++ b/pkg/reconciler/containersource/resources/deployment_test.go @@ -0,0 +1,292 @@ +/* +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 ( + "testing" + + "github.com/google/go-cmp/cmp" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func TestMakeDeployment_sinkoverrideannotationlabelnotallowed(t *testing.T) { + got := MakeDeployment(nil, &ContainerArguments{ + Name: "test-name", + Namespace: "test-namespace", + Image: "test-image", + Args: []string{"--test1=args1", "--test2=args2"}, + Env: []corev1.EnvVar{{ + Name: "test1", + Value: "arg1", + }, { + Name: "test2", + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + Key: "test2-secret", + }, + }, + }}, + ServiceAccountName: "test-service-account", + SinkInArgs: false, + Sink: "test-sink", + Labels: map[string]string{ + "eventing.knative.dev/source": "not-allowed", + "anotherlabel": "extra-label", + }, + Annotations: map[string]string{ + "sidecar.istio.io/inject": "false", + "anotherannotation": "extra-annotation", + }, + }) + + want := &appsv1.Deployment{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "apps/v1", + Kind: "Deployment", + }, + ObjectMeta: metav1.ObjectMeta{ + GenerateName: "test-name-", + Namespace: "test-namespace", + }, + Spec: appsv1.DeploymentSpec{ + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "eventing.knative.dev/source": "test-name", + }, + }, + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + "sidecar.istio.io/inject": "false", + "anotherannotation": "extra-annotation", + }, + Labels: map[string]string{ + "eventing.knative.dev/source": "test-name", + "anotherlabel": "extra-label", + }, + }, + Spec: corev1.PodSpec{ + ServiceAccountName: "test-service-account", + Containers: []corev1.Container{ + { + Name: "source", + Image: "test-image", + Args: []string{ + "--test1=args1", + "--test2=args2", + "--sink=test-sink", + }, + Env: []corev1.EnvVar{ + { + Name: "test1", + Value: "arg1", + }, { + Name: "test2", + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + Key: "test2-secret", + }, + }, + }, { + Name: "SINK", + Value: "test-sink", + }}, + ImagePullPolicy: corev1.PullIfNotPresent, + }, + }, + }, + }, + }, + } + + if diff := cmp.Diff(want, got); diff != "" { + t.Errorf("unexpected deploy (-want, +got) = %v", diff) + } +} + +func TestMakeDeployment_sink(t *testing.T) { + got := MakeDeployment(nil, &ContainerArguments{ + Name: "test-name", + Namespace: "test-namespace", + Image: "test-image", + Args: []string{"--test1=args1", "--test2=args2"}, + Env: []corev1.EnvVar{{ + Name: "test1", + Value: "arg1", + }, { + Name: "test2", + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + Key: "test2-secret", + }, + }, + }}, + ServiceAccountName: "test-service-account", + SinkInArgs: false, + Sink: "test-sink", + }) + + want := &appsv1.Deployment{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "apps/v1", + Kind: "Deployment", + }, + ObjectMeta: metav1.ObjectMeta{ + GenerateName: "test-name-", + Namespace: "test-namespace", + }, + Spec: appsv1.DeploymentSpec{ + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "eventing.knative.dev/source": "test-name", + }, + }, + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + "sidecar.istio.io/inject": "true", + }, + Labels: map[string]string{ + "eventing.knative.dev/source": "test-name", + }, + }, + Spec: corev1.PodSpec{ + ServiceAccountName: "test-service-account", + Containers: []corev1.Container{ + { + Name: "source", + Image: "test-image", + Args: []string{ + "--test1=args1", + "--test2=args2", + "--sink=test-sink", + }, + Env: []corev1.EnvVar{ + { + Name: "test1", + Value: "arg1", + }, { + Name: "test2", + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + Key: "test2-secret", + }, + }, + }, { + Name: "SINK", + Value: "test-sink", + }}, + ImagePullPolicy: corev1.PullIfNotPresent, + }, + }, + }, + }, + }, + } + + if diff := cmp.Diff(want, got); diff != "" { + t.Errorf("unexpected deploy (-want, +got) = %v", diff) + } +} + +func TestMakeDeployment_sinkinargs(t *testing.T) { + got := MakeDeployment(nil, &ContainerArguments{ + Name: "test-name", + Namespace: "test-namespace", + Image: "test-image", + Args: []string{"--test1=args1", "--test2=args2", "--sink=test-sink"}, + Env: []corev1.EnvVar{{ + Name: "test1", + Value: "arg1", + }, { + Name: "test2", + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + Key: "test2-secret", + }, + }, + }}, + ServiceAccountName: "test-service-account", + SinkInArgs: true, + Labels: map[string]string{"eventing.knative.dev/source": "test-name"}, + Annotations: map[string]string{"sidecar.istio.io/inject": "true"}, + }) + + want := &appsv1.Deployment{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "apps/v1", + Kind: "Deployment", + }, + ObjectMeta: metav1.ObjectMeta{ + GenerateName: "test-name-", + Namespace: "test-namespace", + }, + Spec: appsv1.DeploymentSpec{ + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "eventing.knative.dev/source": "test-name", + }, + }, + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + "sidecar.istio.io/inject": "true", + }, + Labels: map[string]string{ + "eventing.knative.dev/source": "test-name", + }, + }, + Spec: corev1.PodSpec{ + ServiceAccountName: "test-service-account", + Containers: []corev1.Container{ + { + Name: "source", + Image: "test-image", + Args: []string{ + "--test1=args1", + "--test2=args2", + "--sink=test-sink", + }, + Env: []corev1.EnvVar{ + { + Name: "test1", + Value: "arg1", + }, { + Name: "test2", + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + Key: "test2-secret", + }, + }, + }, { + Name: "SINK", + Value: "test-sink", + }}, + ImagePullPolicy: corev1.PullIfNotPresent, + }, + }, + }, + }, + }, + } + + if diff := cmp.Diff(want, got); diff != "" { + t.Errorf("unexpected deploy (-want, +got) = %v", diff) + } +} diff --git a/vendor/github.com/knative/eventing-sources/AUTHORS b/vendor/github.com/knative/eventing-sources/AUTHORS new file mode 100644 index 00000000000..9a8f2f769f4 --- /dev/null +++ b/vendor/github.com/knative/eventing-sources/AUTHORS @@ -0,0 +1,6 @@ +# This is the list of Knative authors for copyright purposes. +# +# This does not necessarily list everyone who has contributed code, since in +# some cases, their employer may be the copyright holder. To see the full list +# of contributors, see the revision history in source control. +Google LLC diff --git a/vendor/github.com/knative/eventing-sources/LICENSE b/vendor/github.com/knative/eventing-sources/LICENSE new file mode 100644 index 00000000000..261eeb9e9f8 --- /dev/null +++ b/vendor/github.com/knative/eventing-sources/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/knative/eventing-sources/pkg/apis/sources/v1alpha1/aws_sqs_types.go b/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/aws_sqs_types.go new file mode 100644 index 00000000000..1f93837ce19 --- /dev/null +++ b/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/aws_sqs_types.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 ( + "github.com/knative/pkg/apis/duck" + duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// AwsSqsSource is the Schema for the AWS SQS API +// +k8s:openapi-gen=true +// +kubebuilder:subresource:status +// +kubebuilder:categories=all,knative,eventing,sources +type AwsSqsSource struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec AwsSqsSourceSpec `json:"spec,omitempty"` + Status AwsSqsSourceStatus `json:"status,omitempty"` +} + +// Check that AwsSqsSource can be validated and can be defaulted. +var _ runtime.Object = (*AwsSqsSource)(nil) + +// Check that AwsSqsSource implements the Conditions duck type. +var _ = duck.VerifyType(&AwsSqsSource{}, &duckv1alpha1.Conditions{}) + +// AwsSqsSourceSpec defines the desired state of the source. +type AwsSqsSourceSpec struct { + // QueueURL of the SQS queue that we will poll from. + QueueURL string `json:"queueUrl"` + + // AwsCredsSecret is the credential to use to poll the AWS SQS + AwsCredsSecret corev1.SecretKeySelector `json:"awsCredsSecret,omitempty"` + + // Sink is a reference to an object that will resolve to a domain name to + // use as the sink. This is where events will be received. + // +optional + Sink *corev1.ObjectReference `json:"sink,omitempty"` + + // ServiceAccoutName is the name of the ServiceAccount that will be used to + // run the Receive Adapter Deployment. + ServiceAccountName string `json:"serviceAccountName,omitempty"` +} + +const ( + // AwsSqsSourceConditionReady has status True when the source is + // ready to send events. + AwsSqsSourceConditionReady = duckv1alpha1.ConditionReady + + // AwsSqsSourceConditionSinkProvided has status True when the + // AwsSqsSource has been configured with a sink target. + AwsSqsSourceConditionSinkProvided duckv1alpha1.ConditionType = "SinkProvided" + + // AwsSqsSourceConditionDeployed has status True when the + // AwsSqsSource has had it's receive adapter deployment created. + AwsSqsSourceConditionDeployed duckv1alpha1.ConditionType = "Deployed" +) + +var condSet = duckv1alpha1.NewLivingConditionSet( + AwsSqsSourceConditionReady, + AwsSqsSourceConditionSinkProvided, + AwsSqsSourceConditionDeployed) + +// AwsSqsSourceStatus defines the observed state of the source. +type AwsSqsSourceStatus struct { + // 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"` + + // SinkURI is the current active sink URI that has been configured for the source. + // +optional + SinkURI string `json:"sinkUri,omitempty"` +} + +// GetCondition returns the condition currently associated with the given type, or nil. +func (s *AwsSqsSourceStatus) GetCondition(t duckv1alpha1.ConditionType) *duckv1alpha1.Condition { + return condSet.Manage(s).GetCondition(t) +} + +// IsReady returns true if the resource is ready overall. +func (s *AwsSqsSourceStatus) IsReady() bool { + return condSet.Manage(s).IsHappy() +} + +// InitializeConditions sets relevant unset conditions to Unknown state. +func (s *AwsSqsSourceStatus) InitializeConditions() { + condSet.Manage(s).InitializeConditions() +} + +// MarkSink sets the condition that the source has a sink configured. +func (s *AwsSqsSourceStatus) MarkSink(uri string) { + s.SinkURI = uri + if len(uri) > 0 { + condSet.Manage(s).MarkTrue(AwsSqsSourceConditionSinkProvided) + } else { + condSet.Manage(s).MarkUnknown(AwsSqsSourceConditionSinkProvided, + "SinkEmpty", "Sink has resolved to empty.%s", "") + } +} + +// MarkNoSink sets the condition that the source does not have a sink configured. +func (s *AwsSqsSourceStatus) MarkNoSink(reason, messageFormat string, messageA ...interface{}) { + condSet.Manage(s).MarkFalse(AwsSqsSourceConditionSinkProvided, reason, messageFormat, messageA...) +} + +// MarkDeployed sets the condition that the source has been deployed. +func (s *AwsSqsSourceStatus) MarkDeployed() { + condSet.Manage(s).MarkTrue(AwsSqsSourceConditionDeployed) +} + +// MarkDeploying sets the condition that the source is deploying. +func (s *AwsSqsSourceStatus) MarkDeploying(reason, messageFormat string, messageA ...interface{}) { + condSet.Manage(s).MarkUnknown(AwsSqsSourceConditionDeployed, reason, messageFormat, messageA...) +} + +// MarkNotDeployed sets the condition that the source has not been deployed. +func (s *AwsSqsSourceStatus) MarkNotDeployed(reason, messageFormat string, messageA ...interface{}) { + condSet.Manage(s).MarkFalse(AwsSqsSourceConditionDeployed, reason, messageFormat, messageA...) +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// AwsSqsSourceList contains a list of AwsSqsSource +type AwsSqsSourceList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []AwsSqsSource `json:"items"` +} + +func init() { + SchemeBuilder.Register(&AwsSqsSource{}, &AwsSqsSourceList{}) +} diff --git a/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/containersource_types.go b/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/containersource_types.go new file mode 100644 index 00000000000..4492ca14690 --- /dev/null +++ b/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/containersource_types.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. +*/ + +package v1alpha1 + +import ( + "github.com/knative/pkg/apis/duck" + duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +// Check that ContainerSource can be validated and can be defaulted. +var _ runtime.Object = (*ContainerSource)(nil) + +// Check that ContainerSource implements the Conditions duck type. +var _ = duck.VerifyType(&ContainerSource{}, &duckv1alpha1.Conditions{}) + +// ContainerSourceSpec defines the desired state of ContainerSource +type ContainerSourceSpec struct { + // Image is the image to run inside of the container. + // +kubebuilder:validation:MinLength=1 + Image string `json:"image,omitempty"` + + // Args are passed to the ContainerSpec as they are. + Args []string `json:"args,omitempty"` + + // Env is the list of environment variables to set in the container. + // Cannot be updated. + // +optional + // +patchMergeKey=name + // +patchStrategy=merge + Env []corev1.EnvVar `json:"env,omitempty" patchStrategy:"merge" patchMergeKey:"name"` + + // ServiceAccountName is the name of the ServiceAccount to use to run this + // source. + // +optional + ServiceAccountName string `json:"serviceAccountName,omitempty"` + + // Sink is a reference to an object that will resolve to a domain name to use as the sink. + // +optional + Sink *corev1.ObjectReference `json:"sink,omitempty"` +} + +const ( + // ContainerSourceConditionReady has status True when the ContainerSource is ready to send events. + ContainerConditionReady = duckv1alpha1.ConditionReady + + // ContainerConditionSinkProvided has status True when the ContainerSource has been configured with a sink target. + ContainerConditionSinkProvided duckv1alpha1.ConditionType = "SinkProvided" + + // ContainerConditionDeployed has status True when the ContainerSource has had it's deployment created. + ContainerConditionDeployed duckv1alpha1.ConditionType = "Deployed" +) + +var containerCondSet = duckv1alpha1.NewLivingConditionSet( + ContainerConditionSinkProvided, + ContainerConditionDeployed) + +// ContainerSourceStatus defines the observed state of ContainerSource +type ContainerSourceStatus struct { + // 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"` + + // SinkURI is the current active sink URI that has been configured for the ContainerSource. + // +optional + SinkURI string `json:"sinkUri,omitempty"` +} + +// GetCondition returns the condition currently associated with the given type, or nil. +func (s *ContainerSourceStatus) GetCondition(t duckv1alpha1.ConditionType) *duckv1alpha1.Condition { + return containerCondSet.Manage(s).GetCondition(t) +} + +// IsReady returns true if the resource is ready overall. +func (s *ContainerSourceStatus) IsReady() bool { + return containerCondSet.Manage(s).IsHappy() +} + +// InitializeConditions sets relevant unset conditions to Unknown state. +func (s *ContainerSourceStatus) InitializeConditions() { + containerCondSet.Manage(s).InitializeConditions() +} + +// MarSink sets the condition that the source has a sink configured. +func (s *ContainerSourceStatus) MarkSink(uri string) { + s.SinkURI = uri + if len(uri) > 0 { + containerCondSet.Manage(s).MarkTrue(ContainerConditionSinkProvided) + } else { + containerCondSet.Manage(s).MarkUnknown(ContainerConditionSinkProvided, "SinkEmpty", "Sink has resolved to empty.%s", "") + } +} + +// MarkNoSink sets the condition that the source does not have a sink configured. +func (s *ContainerSourceStatus) MarkNoSink(reason, messageFormat string, messageA ...interface{}) { + containerCondSet.Manage(s).MarkFalse(ContainerConditionSinkProvided, reason, messageFormat, messageA...) +} + +// MarkDeployed sets the condition that the source has been deployed. +func (s *ContainerSourceStatus) MarkDeployed() { + containerCondSet.Manage(s).MarkTrue(ContainerConditionDeployed) +} + +// MarkDeploying sets the condition that the source is deploying. +func (s *ContainerSourceStatus) MarkDeploying(reason, messageFormat string, messageA ...interface{}) { + containerCondSet.Manage(s).MarkUnknown(ContainerConditionDeployed, reason, messageFormat, messageA...) +} + +// MarkNotDeployed sets the condition that the source has not been deployed. +func (s *ContainerSourceStatus) MarkNotDeployed(reason, messageFormat string, messageA ...interface{}) { + containerCondSet.Manage(s).MarkFalse(ContainerConditionDeployed, reason, messageFormat, messageA...) +} + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// ContainerSource is the Schema for the containersources API +// +k8s:openapi-gen=true +// +kubebuilder:subresource:status +// +kubebuilder:categories=all,knative,eventing,sources +type ContainerSource struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec ContainerSourceSpec `json:"spec,omitempty"` + Status ContainerSourceStatus `json:"status,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// ContainerSourceList contains a list of ContainerSource +type ContainerSourceList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []ContainerSource `json:"items"` +} + +func init() { + SchemeBuilder.Register(&ContainerSource{}, &ContainerSourceList{}) +} diff --git a/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/cron_job_types.go b/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/cron_job_types.go new file mode 100644 index 00000000000..aaeffc74e89 --- /dev/null +++ b/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/cron_job_types.go @@ -0,0 +1,164 @@ +/* +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/duck" + duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// CronJobSource is the Schema for the cronjobsources API. +// +k8s:openapi-gen=true +// +kubebuilder:subresource:status +// +kubebuilder:categories=all,knative,eventing,sources +type CronJobSource struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec CronJobSourceSpec `json:"spec,omitempty"` + Status CronJobSourceStatus `json:"status,omitempty"` +} + +// Check that CronJobSource can be validated and can be defaulted. +var _ runtime.Object = (*CronJobSource)(nil) + +// Check that CronJobSource implements the Conditions duck type. +var _ = duck.VerifyType(&CronJobSource{}, &duckv1alpha1.Conditions{}) + +// CronJobSourceSpec defines the desired state of the CronJobSource. +type CronJobSourceSpec struct { + + // Schedule is the cronjob schedule. + // +required + Schedule string `json:"schedule"` + + // Data is the data posted to the target function. + Data string `json:"data,omitempty"` + + // Sink is a reference to an object that will resolve to a domain name to use as the sink. + // +optional + Sink *corev1.ObjectReference `json:"sink,omitempty"` + + // ServiceAccoutName is the name of the ServiceAccount that will be used to run the Receive + // Adapter Deployment. + ServiceAccountName string `json:"serviceAccountName,omitempty"` +} + +const ( + // CronJobConditionReady has status True when the CronJobSource is ready to send events. + CronJobConditionReady = duckv1alpha1.ConditionReady + + // CronJobConditionValidSchedule has status True when the CronJobSource has been configured with a valid schedule. + CronJobConditionValidSchedule duckv1alpha1.ConditionType = "ValidSchedule" + + // CronJobConditionSinkProvided has status True when the CronJobSource has been configured with a sink target. + CronJobConditionSinkProvided duckv1alpha1.ConditionType = "SinkProvided" + + // CronJobConditionDeployed has status True when the CronJobSource has had it's receive adapter deployment created. + CronJobConditionDeployed duckv1alpha1.ConditionType = "Deployed" +) + +var cronJobSourceCondSet = duckv1alpha1.NewLivingConditionSet( + CronJobConditionValidSchedule, + CronJobConditionSinkProvided, + CronJobConditionDeployed) + +// CronJobSourceStatus defines the observed state of CronJobSource. +type CronJobSourceStatus struct { + // 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"` + + // SinkURI is the current active sink URI that has been configured for the CronJobSource. + // +optional + SinkURI string `json:"sinkUri,omitempty"` +} + +// GetCondition returns the condition currently associated with the given type, or nil. +func (s *CronJobSourceStatus) GetCondition(t duckv1alpha1.ConditionType) *duckv1alpha1.Condition { + return cronJobSourceCondSet.Manage(s).GetCondition(t) +} + +// IsReady returns true if the resource is ready overall. +func (s *CronJobSourceStatus) IsReady() bool { + return cronJobSourceCondSet.Manage(s).IsHappy() +} + +// InitializeConditions sets relevant unset conditions to Unknown state. +func (s *CronJobSourceStatus) InitializeConditions() { + cronJobSourceCondSet.Manage(s).InitializeConditions() +} + +// MarkSchedule sets the condition that the source has a valid schedule configured. +func (s *CronJobSourceStatus) MarkSchedule() { + cronJobSourceCondSet.Manage(s).MarkTrue(CronJobConditionValidSchedule) +} + +// MarkInvalidSchedule sets the condition that the source does not have a valid schedule configured. +func (s *CronJobSourceStatus) MarkInvalidSchedule(reason, messageFormat string, messageA ...interface{}) { + cronJobSourceCondSet.Manage(s).MarkFalse(CronJobConditionValidSchedule, reason, messageFormat, messageA...) +} + +// MarkSink sets the condition that the source has a sink configured. +func (s *CronJobSourceStatus) MarkSink(uri string) { + s.SinkURI = uri + if len(uri) > 0 { + cronJobSourceCondSet.Manage(s).MarkTrue(CronJobConditionSinkProvided) + } else { + cronJobSourceCondSet.Manage(s).MarkUnknown(CronJobConditionSinkProvided, "SinkEmpty", "Sink has resolved to empty.%s", "") + } +} + +// MarkNoSink sets the condition that the source does not have a sink configured. +func (s *CronJobSourceStatus) MarkNoSink(reason, messageFormat string, messageA ...interface{}) { + cronJobSourceCondSet.Manage(s).MarkFalse(CronJobConditionSinkProvided, reason, messageFormat, messageA...) +} + +// MarkDeployed sets the condition that the source has been deployed. +func (s *CronJobSourceStatus) MarkDeployed() { + cronJobSourceCondSet.Manage(s).MarkTrue(CronJobConditionDeployed) +} + +// MarkDeploying sets the condition that the source is deploying. +func (s *CronJobSourceStatus) MarkDeploying(reason, messageFormat string, messageA ...interface{}) { + cronJobSourceCondSet.Manage(s).MarkUnknown(CronJobConditionDeployed, reason, messageFormat, messageA...) +} + +// MarkNotDeployed sets the condition that the source has not been deployed. +func (s *CronJobSourceStatus) MarkNotDeployed(reason, messageFormat string, messageA ...interface{}) { + cronJobSourceCondSet.Manage(s).MarkFalse(CronJobConditionDeployed, reason, messageFormat, messageA...) +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// CronJobSourceList contains a list of CronJobSources. +type CronJobSourceList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []CronJobSource `json:"items"` +} + +func init() { + SchemeBuilder.Register(&CronJobSource{}, &CronJobSourceList{}) +} diff --git a/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/doc.go b/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/doc.go new file mode 100644 index 00000000000..258a98c9176 --- /dev/null +++ b/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/doc.go @@ -0,0 +1,23 @@ +/* +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 contains API Schema definitions for the sources v1alpha1 API group +// +k8s:openapi-gen=true +// +k8s:deepcopy-gen=package,register +// +k8s:conversion-gen=github.com/knative/eventing-sources/pkg/apis/sources +// +k8s:defaulter-gen=TypeMeta +// +groupName=sources.eventing.knative.dev +package v1alpha1 diff --git a/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/githubsource_types.go b/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/githubsource_types.go new file mode 100644 index 00000000000..808e0fc9542 --- /dev/null +++ b/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/githubsource_types.go @@ -0,0 +1,195 @@ +/* +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/duck" + duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +// Check that GitHubSource can be validated and can be defaulted. +var _ runtime.Object = (*GitHubSource)(nil) + +// Check that GitHubSource implements the Conditions duck type. +var _ = duck.VerifyType(&GitHubSource{}, &duckv1alpha1.Conditions{}) + +// GitHubSourceSpec defines the desired state of GitHubSource +// +kubebuilder:categories=all,knative,eventing,sources +type GitHubSourceSpec struct { + // ServiceAccountName holds the name of the Kubernetes service account + // as which the underlying K8s resources should be run. If unspecified + // this will default to the "default" service account for the namespace + // in which the GitHubSource exists. + // +optional + ServiceAccountName string `json:"serviceAccountName,omitempty"` + + // OwnerAndRepository is the GitHub owner/org and repository to + // receive events from. The repository may be left off to receive + // events from an entire organization. + // Examples: + // myuser/project + // myorganization + // +kubebuilder:validation:MinLength=1 + OwnerAndRepository string `json:"ownerAndRepository"` + + // EventType is the type of event to receive from GitHub. These + // correspond to the "Webhook event name" values listed at + // https://developer.github.com/v3/activity/events/types/ - ie + // "pull_request" + // +kubebuilder:validation:MinItems=1 + // +kubebuilder:validation:Enum=commit_comment,create,delete,deployment,deployment_status,fork,gollum,installation,integration_installation,issue_comment,issues,label,member,membership,milestone,organization,org_block,page_build,ping,project_card,project_column,project,public,pull_request,pull_request_review,pull_request_review_comment,push,release,repository,status,team,team_add,watch + EventTypes []string `json:"eventTypes"` + + // AccessToken is the Kubernetes secret containing the GitHub + // access token + AccessToken SecretValueFromSource `json:"accessToken"` + + // SecretToken is the Kubernetes secret containing the GitHub + // secret token + SecretToken SecretValueFromSource `json:"secretToken"` + + // Sink is a reference to an object that will resolve to a domain + // name to use as the sink. + // +optional + Sink *corev1.ObjectReference `json:"sink,omitempty"` + + // API URL if using github enterprise (default https://api.github.com) + // +optional + GitHubAPIURL string `json:"githubAPIURL,omitempty"` + + // Secure can be set to true to configure the webhook to use https. + // +optional + Secure bool `json:"secure,omitempty"` +} + +// SecretValueFromSource represents the source of a secret value +type SecretValueFromSource struct { + // The Secret key to select from. + SecretKeyRef *corev1.SecretKeySelector `json:"secretKeyRef,omitempty"` +} + +const ( + // GitHubSourceEventPrefix is what all GitHub event types get + // prefixed with when converting to CloudEvent EventType + GitHubSourceEventPrefix = "dev.knative.source.github" +) + +const ( + // GitHubSourceConditionReady has status True when the + // GitHubSource is ready to send events. + GitHubSourceConditionReady = duckv1alpha1.ConditionReady + + // GitHubSourceConditionSecretsProvided has status True when the + // GitHubSource has valid secret references + GitHubSourceConditionSecretsProvided duckv1alpha1.ConditionType = "SecretsProvided" + + // GitHubSourceConditionSinkProvided has status True when the + // GitHubSource has been configured with a sink target. + GitHubSourceConditionSinkProvided duckv1alpha1.ConditionType = "SinkProvided" +) + +var gitHubSourceCondSet = duckv1alpha1.NewLivingConditionSet( + GitHubSourceConditionSecretsProvided, + GitHubSourceConditionSinkProvided) + +// GitHubSourceStatus defines the observed state of GitHubSource +type GitHubSourceStatus struct { + // 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"` + + // WebhookIDKey is the ID of the webhook registered with GitHub + WebhookIDKey string `json:"webhookIDKey,omitempty"` + + // SinkURI is the current active sink URI that has been configured + // for the GitHubSource. + // +optional + SinkURI string `json:"sinkUri,omitempty"` +} + +// GetCondition returns the condition currently associated with the given type, or nil. +func (s *GitHubSourceStatus) GetCondition(t duckv1alpha1.ConditionType) *duckv1alpha1.Condition { + return gitHubSourceCondSet.Manage(s).GetCondition(t) +} + +// IsReady returns true if the resource is ready overall. +func (s *GitHubSourceStatus) IsReady() bool { + return gitHubSourceCondSet.Manage(s).IsHappy() +} + +// InitializeConditions sets relevant unset conditions to Unknown state. +func (s *GitHubSourceStatus) InitializeConditions() { + gitHubSourceCondSet.Manage(s).InitializeConditions() +} + +// MarkSecrets sets the condition that the source has a valid spec +func (s *GitHubSourceStatus) MarkSecrets() { + gitHubSourceCondSet.Manage(s).MarkTrue(GitHubSourceConditionSecretsProvided) +} + +// MarkNoSecrets sets the condition that the source does not have a valid spec +func (s *GitHubSourceStatus) MarkNoSecrets(reason, messageFormat string, messageA ...interface{}) { + gitHubSourceCondSet.Manage(s).MarkFalse(GitHubSourceConditionSecretsProvided, reason, messageFormat, messageA...) +} + +// MarkSink sets the condition that the source has a sink configured. +func (s *GitHubSourceStatus) MarkSink(uri string) { + s.SinkURI = uri + if len(uri) > 0 { + gitHubSourceCondSet.Manage(s).MarkTrue(GitHubSourceConditionSinkProvided) + } else { + gitHubSourceCondSet.Manage(s).MarkUnknown(GitHubSourceConditionSinkProvided, + "SinkEmpty", "Sink has resolved to empty.") + } +} + +// MarkNoSink sets the condition that the source does not have a sink configured. +func (s *GitHubSourceStatus) MarkNoSink(reason, messageFormat string, messageA ...interface{}) { + gitHubSourceCondSet.Manage(s).MarkFalse(GitHubSourceConditionSinkProvided, reason, messageFormat, messageA...) +} + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// GitHubSource is the Schema for the githubsources API +// +k8s:openapi-gen=true +// +kubebuilder:subresource:status +// +kubebuilder:categories=all,knative,eventing,sources +type GitHubSource struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec GitHubSourceSpec `json:"spec,omitempty"` + Status GitHubSourceStatus `json:"status,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// GitHubSourceList contains a list of GitHubSource +type GitHubSourceList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []GitHubSource `json:"items"` +} + +func init() { + SchemeBuilder.Register(&GitHubSource{}, &GitHubSourceList{}) +} diff --git a/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/kuberneteseventsource_types.go b/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/kuberneteseventsource_types.go new file mode 100644 index 00000000000..39c5394198a --- /dev/null +++ b/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/kuberneteseventsource_types.go @@ -0,0 +1,122 @@ +/* +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/duck" + duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +// Check that KubernetesEventSource can be validated and can be defaulted. +var _ runtime.Object = (*KubernetesEventSource)(nil) + +// Check that KubernetesEventSource implements the Conditions duck type. +var _ = duck.VerifyType(&KubernetesEventSource{}, &duckv1alpha1.Conditions{}) + +// KubernetesEventSourceSpec defines the desired state of the source. +type KubernetesEventSourceSpec struct { + // Namespace that we watch kubernetes events in. + Namespace string `json:"namespace"` + + // ServiceAccountName is the name of the ServiceAccount to use to run this + // source. + // +optional + ServiceAccountName string `json:"serviceAccountName,omitempty"` + + // Sink is a reference to an object that will resolve to a domain name to use + // as the sink. + // +optional + Sink *corev1.ObjectReference `json:"sink,omitempty"` +} + +const ( + // KubernetesEventSourceConditionReady has status True when the + // source is ready to send events. + KubernetesEventSourceConditionReady = duckv1alpha1.ConditionReady +) + +var kubernetesEventSourceCondSet = duckv1alpha1.NewLivingConditionSet() + +// KubernetesEventSourceStatus defines the observed state of the source. +type KubernetesEventSourceStatus struct { + // 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"` + + // SinkURI is the current active sink URI that has been configured for the source. + // +optional + SinkURI string `json:"sinkUri,omitempty"` +} + +// GetCondition returns the condition currently associated with the given type, or nil. +func (s *KubernetesEventSourceStatus) GetCondition(t duckv1alpha1.ConditionType) *duckv1alpha1.Condition { + return kubernetesEventSourceCondSet.Manage(s).GetCondition(t) +} + +// IsReady returns true if the resource is ready overall. +func (s *KubernetesEventSourceStatus) IsReady() bool { + return kubernetesEventSourceCondSet.Manage(s).IsHappy() +} + +// InitializeConditions sets relevant unset conditions to Unknown state. +func (s *KubernetesEventSourceStatus) InitializeConditions() { + kubernetesEventSourceCondSet.Manage(s).InitializeConditions() +} + +// MarkReady sets the condition that the ContainerSource owned by +// the source has Ready status True. +func (s *KubernetesEventSourceStatus) MarkReady() { + kubernetesEventSourceCondSet.Manage(s).MarkTrue(KubernetesEventSourceConditionReady) +} + +// MarkUnready sets the condition that the ContainerSource owned by +// the source does not have Ready status True. +func (s *KubernetesEventSourceStatus) MarkUnready(reason, messageFormat string, messageA ...interface{}) { + kubernetesEventSourceCondSet.Manage(s).MarkFalse(KubernetesEventSourceConditionReady, reason, messageFormat, messageA...) +} + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// KubernetesEventSource is the Schema for the kuberneteseventsources API +// +k8s:openapi-gen=true +// +kubebuilder:subresource:status +// +kubebuilder:categories=all,knative,eventing,sources +type KubernetesEventSource struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec KubernetesEventSourceSpec `json:"spec,omitempty"` + Status KubernetesEventSourceStatus `json:"status,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// KubernetesEventSourceList contains a list of KubernetesEventSource +type KubernetesEventSourceList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []KubernetesEventSource `json:"items"` +} + +func init() { + SchemeBuilder.Register(&KubernetesEventSource{}, &KubernetesEventSourceList{}) +} diff --git a/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/register.go b/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/register.go new file mode 100644 index 00000000000..fa5f80118ce --- /dev/null +++ b/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/register.go @@ -0,0 +1,45 @@ +/* +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. +*/ + +// NOTE: Boilerplate only. Ignore this file. + +// Package v1alpha1 contains API Schema definitions for the sources v1alpha1 API group +// +k8s:openapi-gen=true +// +k8s:deepcopy-gen=package,register +// +k8s:conversion-gen=github.com/knative/eventing-sources/pkg/apis/sources +// +k8s:defaulter-gen=TypeMeta +// +groupName=sources.eventing.knative.dev +package v1alpha1 + +import ( + "k8s.io/apimachinery/pkg/runtime/schema" + "sigs.k8s.io/controller-runtime/pkg/runtime/scheme" +) + +var ( + // SchemeGroupVersion is group version used to register these objects + SchemeGroupVersion = schema.GroupVersion{Group: "sources.eventing.knative.dev", Version: "v1alpha1"} + + // SchemeBuilder is used to add go types to the GroupVersionKind scheme + SchemeBuilder = &scheme.Builder{GroupVersion: SchemeGroupVersion} + + AddToScheme = SchemeBuilder.AddToScheme +) + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} diff --git a/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/zz_generated.deepcopy.go b/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/zz_generated.deepcopy.go new file mode 100644 index 00000000000..2dbe589a81f --- /dev/null +++ b/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/zz_generated.deepcopy.go @@ -0,0 +1,562 @@ +// +build !ignore_autogenerated + +/* +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 deepcopy-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + v1 "k8s.io/api/core/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 *AwsSqsSource) DeepCopyInto(out *AwsSqsSource) { + *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 AwsSqsSource. +func (in *AwsSqsSource) DeepCopy() *AwsSqsSource { + if in == nil { + return nil + } + out := new(AwsSqsSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *AwsSqsSource) 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 *AwsSqsSourceList) DeepCopyInto(out *AwsSqsSourceList) { + *out = *in + out.TypeMeta = in.TypeMeta + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]AwsSqsSource, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AwsSqsSourceList. +func (in *AwsSqsSourceList) DeepCopy() *AwsSqsSourceList { + if in == nil { + return nil + } + out := new(AwsSqsSourceList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *AwsSqsSourceList) 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 *AwsSqsSourceSpec) DeepCopyInto(out *AwsSqsSourceSpec) { + *out = *in + in.AwsCredsSecret.DeepCopyInto(&out.AwsCredsSecret) + if in.Sink != nil { + in, out := &in.Sink, &out.Sink + *out = new(v1.ObjectReference) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AwsSqsSourceSpec. +func (in *AwsSqsSourceSpec) DeepCopy() *AwsSqsSourceSpec { + if in == nil { + return nil + } + out := new(AwsSqsSourceSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AwsSqsSourceStatus) DeepCopyInto(out *AwsSqsSourceStatus) { + *out = *in + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AwsSqsSourceStatus. +func (in *AwsSqsSourceStatus) DeepCopy() *AwsSqsSourceStatus { + if in == nil { + return nil + } + out := new(AwsSqsSourceStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ContainerSource) DeepCopyInto(out *ContainerSource) { + *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 ContainerSource. +func (in *ContainerSource) DeepCopy() *ContainerSource { + if in == nil { + return nil + } + out := new(ContainerSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ContainerSource) 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 *ContainerSourceList) DeepCopyInto(out *ContainerSourceList) { + *out = *in + out.TypeMeta = in.TypeMeta + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]ContainerSource, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ContainerSourceList. +func (in *ContainerSourceList) DeepCopy() *ContainerSourceList { + if in == nil { + return nil + } + out := new(ContainerSourceList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ContainerSourceList) 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 *ContainerSourceSpec) DeepCopyInto(out *ContainerSourceSpec) { + *out = *in + if in.Args != nil { + in, out := &in.Args, &out.Args + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Env != nil { + in, out := &in.Env, &out.Env + *out = make([]v1.EnvVar, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Sink != nil { + in, out := &in.Sink, &out.Sink + *out = new(v1.ObjectReference) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ContainerSourceSpec. +func (in *ContainerSourceSpec) DeepCopy() *ContainerSourceSpec { + if in == nil { + return nil + } + out := new(ContainerSourceSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ContainerSourceStatus) DeepCopyInto(out *ContainerSourceStatus) { + *out = *in + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ContainerSourceStatus. +func (in *ContainerSourceStatus) DeepCopy() *ContainerSourceStatus { + if in == nil { + return nil + } + out := new(ContainerSourceStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CronJobSource) DeepCopyInto(out *CronJobSource) { + *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 CronJobSource. +func (in *CronJobSource) DeepCopy() *CronJobSource { + if in == nil { + return nil + } + out := new(CronJobSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *CronJobSource) 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 *CronJobSourceList) DeepCopyInto(out *CronJobSourceList) { + *out = *in + out.TypeMeta = in.TypeMeta + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]CronJobSource, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CronJobSourceList. +func (in *CronJobSourceList) DeepCopy() *CronJobSourceList { + if in == nil { + return nil + } + out := new(CronJobSourceList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *CronJobSourceList) 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 *CronJobSourceSpec) DeepCopyInto(out *CronJobSourceSpec) { + *out = *in + if in.Sink != nil { + in, out := &in.Sink, &out.Sink + *out = new(v1.ObjectReference) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CronJobSourceSpec. +func (in *CronJobSourceSpec) DeepCopy() *CronJobSourceSpec { + if in == nil { + return nil + } + out := new(CronJobSourceSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CronJobSourceStatus) DeepCopyInto(out *CronJobSourceStatus) { + *out = *in + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CronJobSourceStatus. +func (in *CronJobSourceStatus) DeepCopy() *CronJobSourceStatus { + if in == nil { + return nil + } + out := new(CronJobSourceStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GitHubSource) DeepCopyInto(out *GitHubSource) { + *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 GitHubSource. +func (in *GitHubSource) DeepCopy() *GitHubSource { + if in == nil { + return nil + } + out := new(GitHubSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *GitHubSource) 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 *GitHubSourceList) DeepCopyInto(out *GitHubSourceList) { + *out = *in + out.TypeMeta = in.TypeMeta + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]GitHubSource, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GitHubSourceList. +func (in *GitHubSourceList) DeepCopy() *GitHubSourceList { + if in == nil { + return nil + } + out := new(GitHubSourceList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *GitHubSourceList) 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 *GitHubSourceSpec) DeepCopyInto(out *GitHubSourceSpec) { + *out = *in + if in.EventTypes != nil { + in, out := &in.EventTypes, &out.EventTypes + *out = make([]string, len(*in)) + copy(*out, *in) + } + in.AccessToken.DeepCopyInto(&out.AccessToken) + in.SecretToken.DeepCopyInto(&out.SecretToken) + if in.Sink != nil { + in, out := &in.Sink, &out.Sink + *out = new(v1.ObjectReference) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GitHubSourceSpec. +func (in *GitHubSourceSpec) DeepCopy() *GitHubSourceSpec { + if in == nil { + return nil + } + out := new(GitHubSourceSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GitHubSourceStatus) DeepCopyInto(out *GitHubSourceStatus) { + *out = *in + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GitHubSourceStatus. +func (in *GitHubSourceStatus) DeepCopy() *GitHubSourceStatus { + if in == nil { + return nil + } + out := new(GitHubSourceStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KubernetesEventSource) DeepCopyInto(out *KubernetesEventSource) { + *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 KubernetesEventSource. +func (in *KubernetesEventSource) DeepCopy() *KubernetesEventSource { + if in == nil { + return nil + } + out := new(KubernetesEventSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *KubernetesEventSource) 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 *KubernetesEventSourceList) DeepCopyInto(out *KubernetesEventSourceList) { + *out = *in + out.TypeMeta = in.TypeMeta + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]KubernetesEventSource, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubernetesEventSourceList. +func (in *KubernetesEventSourceList) DeepCopy() *KubernetesEventSourceList { + if in == nil { + return nil + } + out := new(KubernetesEventSourceList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *KubernetesEventSourceList) 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 *KubernetesEventSourceSpec) DeepCopyInto(out *KubernetesEventSourceSpec) { + *out = *in + if in.Sink != nil { + in, out := &in.Sink, &out.Sink + *out = new(v1.ObjectReference) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubernetesEventSourceSpec. +func (in *KubernetesEventSourceSpec) DeepCopy() *KubernetesEventSourceSpec { + if in == nil { + return nil + } + out := new(KubernetesEventSourceSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KubernetesEventSourceStatus) DeepCopyInto(out *KubernetesEventSourceStatus) { + *out = *in + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubernetesEventSourceStatus. +func (in *KubernetesEventSourceStatus) DeepCopy() *KubernetesEventSourceStatus { + if in == nil { + return nil + } + out := new(KubernetesEventSourceStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SecretValueFromSource) DeepCopyInto(out *SecretValueFromSource) { + *out = *in + if in.SecretKeyRef != nil { + in, out := &in.SecretKeyRef, &out.SecretKeyRef + *out = new(v1.SecretKeySelector) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretValueFromSource. +func (in *SecretValueFromSource) DeepCopy() *SecretValueFromSource { + if in == nil { + return nil + } + out := new(SecretValueFromSource) + in.DeepCopyInto(out) + return out +} diff --git a/vendor/github.com/knative/eventing-sources/pkg/controller/sdk/finalizers_accessor.go b/vendor/github.com/knative/eventing-sources/pkg/controller/sdk/finalizers_accessor.go new file mode 100644 index 00000000000..f7545ab0d7a --- /dev/null +++ b/vendor/github.com/knative/eventing-sources/pkg/controller/sdk/finalizers_accessor.go @@ -0,0 +1,82 @@ +/* +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 sdk + +import ( + "errors" + "fmt" + "reflect" + + "k8s.io/apimachinery/pkg/util/sets" +) + +// FinalizersAccessor is the interface for a Resource that implements the getter and setting for +// accessing its Finalizer set. +// +k8s:deepcopy-gen=true +type FinalizersAccessor interface { + GetFinalizers() sets.String + SetFinalizers(finalizers sets.String) +} + +// NewReflectedFinalizersAccessor uses reflection to return a FinalizersAccessor to access the field +// called "Finalizers". +func NewReflectedFinalizersAccessor(object interface{}) (FinalizersAccessor, error) { + objectValue := reflect.Indirect(reflect.ValueOf(object)) + + // If object is not a struct, don't even try to use it. + if objectValue.Kind() != reflect.Struct { + return nil, errors.New("object is not a struct") + } + + finalizersField := objectValue.FieldByName("Finalizers") + if finalizersField.IsValid() && finalizersField.CanSet() && finalizersField.Kind() == reflect.Slice { + finalizers := sets.NewString() + for i := 0; i < finalizersField.Len(); i++ { + finalizer := finalizersField.Index(i) + if finalizer.IsValid() && finalizer.Kind() == reflect.String { + finalizers.Insert(finalizer.String()) + } else { + return nil, fmt.Errorf("element in the Finalizer slice was not a string: %v", finalizer.Kind()) + } + } + return &reflectedFinalizersAccessor{ + finalizersField: finalizersField, + finalizersSet: finalizers, + }, nil + } + + return nil, fmt.Errorf("finalizer was not a slice: %v", finalizersField.Kind()) +} + +// reflectedFinalizersAccessor is an internal wrapper object to act as the FinalizersAccessor for +// objects that do not implement FinalizersAccessor directly, but do expose the field using the +// name "Finalizers". +type reflectedFinalizersAccessor struct { + finalizersField reflect.Value + finalizersSet sets.String +} + +// GetFinalizers uses reflection to return the Finalizers set from the held object. +func (r *reflectedFinalizersAccessor) GetFinalizers() sets.String { + return r.finalizersSet +} + +// SetFinalizers uses reflection to set Finalizers on the held object. +func (r *reflectedFinalizersAccessor) SetFinalizers(finalizers sets.String) { + r.finalizersSet = finalizers + r.finalizersField.Set(reflect.ValueOf(finalizers.List())) +} diff --git a/vendor/github.com/knative/eventing-sources/pkg/controller/sdk/provider.go b/vendor/github.com/knative/eventing-sources/pkg/controller/sdk/provider.go new file mode 100644 index 00000000000..664de9daf0e --- /dev/null +++ b/vendor/github.com/knative/eventing-sources/pkg/controller/sdk/provider.go @@ -0,0 +1,74 @@ +/* +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 sdk + +import ( + "context" + + "k8s.io/apimachinery/pkg/runtime" + "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/runtime/inject" + "sigs.k8s.io/controller-runtime/pkg/source" +) + +type KnativeReconciler interface { + Reconcile(ctx context.Context, object runtime.Object) error + inject.Client +} + +type Provider struct { + AgentName string + // Parent is a resource kind to reconcile with empty content. i.e. &v1.Parent{} + Parent runtime.Object + // Owns are dependent resources owned by the parent for which changes to + // those resources cause the Parent to be re-reconciled. This is a list of + // resources of kind with empty content. i.e. [&v1.Child{}] + Owns []runtime.Object + + Reconciler KnativeReconciler +} + +// ProvideController returns a controller for controller-runtime. +func (p *Provider) Add(mgr manager.Manager) error { + // Setup a new controller to Reconcile Subscriptions. + c, err := controller.New(p.AgentName, mgr, controller.Options{ + Reconciler: &Reconciler{ + provider: *p, + recorder: mgr.GetRecorder(p.AgentName), + }, + }) + if err != nil { + return err + } + + // Watch Parent events and enqueue Parent object key. + if err := c.Watch(&source.Kind{Type: p.Parent}, &handler.EnqueueRequestForObject{}); err != nil { + return err + } + + // Watch and enqueue for owning obj key. + for _, t := range p.Owns { + if err := c.Watch(&source.Kind{Type: t}, + &handler.EnqueueRequestForOwner{OwnerType: p.Parent, IsController: true}); err != nil { + return err + } + } + + return nil +} diff --git a/vendor/github.com/knative/eventing-sources/pkg/controller/sdk/reconciler.go b/vendor/github.com/knative/eventing-sources/pkg/controller/sdk/reconciler.go new file mode 100644 index 00000000000..58d39d25122 --- /dev/null +++ b/vendor/github.com/knative/eventing-sources/pkg/controller/sdk/reconciler.go @@ -0,0 +1,186 @@ +/* +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 sdk + +import ( + "context" + + "go.uber.org/zap" + + "github.com/knative/pkg/logging" + "k8s.io/apimachinery/pkg/api/equality" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/record" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + "sigs.k8s.io/controller-runtime/pkg/runtime/inject" +) + +type Reconciler struct { + client client.Client + recorder record.EventRecorder + scheme *runtime.Scheme + + provider Provider +} + +// Verify the struct implements reconcile.Reconciler +var _ reconcile.Reconciler = &Reconciler{} + +// Reconcile compares the actual state with the desired, and attempts to +// converge the two. +func (r *Reconciler) Reconcile(request reconcile.Request) (reconcile.Result, error) { + ctx := context.TODO() + logger := logging.FromContext(ctx) + + logger.Infof("Reconciling %s %v", r.provider.Parent.GetObjectKind(), request) + + original := r.provider.Parent.DeepCopyObject() + + err := r.client.Get(context.TODO(), request.NamespacedName, original) + + if errors.IsNotFound(err) { + logger.Errorf("could not find %s %v\n", r.provider.Parent.GetObjectKind(), request) + return reconcile.Result{}, nil + } + + if err != nil { + logger.Errorf("could not fetch %s %v for %+v\n", r.provider.Parent.GetObjectKind(), err, request) + return reconcile.Result{}, err + } + + // Don't modify the cache's copy + obj := original.DeepCopyObject() + + // Reconcile this copy of the Source and then write back any status + // updates regardless of whether the reconcile error out. + reconcileErr := r.provider.Reconciler.Reconcile(ctx, obj) + if reconcileErr != nil { + logger.Warnf("Failed to reconcile %s: %v", r.provider.Parent.GetObjectKind(), reconcileErr) + } + + if needsUpdate, err := r.needsUpdate(ctx, original, obj); err != nil { + logger.Desugar().Error("Unable to determine if an update is needed", zap.Error(err), zap.Any("original", original), zap.Any("obj", obj)) + return reconcile.Result{}, err + } else if needsUpdate { + if _, err := r.update(ctx, request, obj); err != nil { + logger.Desugar().Error("Failed to update", zap.Error(err), zap.Any("objectKind", r.provider.Parent.GetObjectKind())) + return reconcile.Result{}, err + } + } + + // Requeue if the resource is not ready: + return reconcile.Result{}, reconcileErr +} + +func (r *Reconciler) InjectClient(c client.Client) error { + r.client = c + _, err := inject.ClientInto(c, r.provider.Reconciler) + return err +} + +func (r *Reconciler) InjectConfig(c *rest.Config) error { + _, err := inject.ConfigInto(c, r.provider.Reconciler) + return err +} + +func (r *Reconciler) needsUpdate(ctx context.Context, old, new runtime.Object) (bool, error) { + if old == nil { + return true, nil + } + + // Check Status. + os, err := NewReflectedStatusAccessor(old) + if err != nil { + return false, err + } + ns, err := NewReflectedStatusAccessor(new) + if err != nil { + return false, err + } + oStatus := os.GetStatus() + nStatus := ns.GetStatus() + + if !equality.Semantic.DeepEqual(oStatus, nStatus) { + return true, nil + } + + // Check finalizers. + of, err := NewReflectedFinalizersAccessor(old) + if err != nil { + return false, err + } + nf, err := NewReflectedFinalizersAccessor(new) + if err != nil { + return false, err + } + oFinalizers := of.GetFinalizers() + nFinalizers := nf.GetFinalizers() + + if !equality.Semantic.DeepEqual(oFinalizers, nFinalizers) { + return true, nil + } + + return false, nil +} + +func (r *Reconciler) update(ctx context.Context, request reconcile.Request, object runtime.Object) (runtime.Object, error) { + freshObj := r.provider.Parent.DeepCopyObject() + if err := r.client.Get(ctx, request.NamespacedName, freshObj); err != nil { + return nil, err + } + + // Finalizers + freshFinalizers, err := NewReflectedFinalizersAccessor(freshObj) + if err != nil { + return nil, err + } + orgFinalizers, err := NewReflectedFinalizersAccessor(object) + if err != nil { + return nil, err + } + freshFinalizers.SetFinalizers(orgFinalizers.GetFinalizers()) + + if err := r.client.Update(ctx, freshObj); err != nil { + return nil, err + } + + // Refetch + freshObj = r.provider.Parent.DeepCopyObject() + if err := r.client.Get(ctx, request.NamespacedName, freshObj); err != nil { + return nil, err + } + + // Status + freshStatus, err := NewReflectedStatusAccessor(freshObj) + if err != nil { + return nil, err + } + orgStatus, err := NewReflectedStatusAccessor(object) + if err != nil { + return nil, err + } + freshStatus.SetStatus(orgStatus.GetStatus()) + + if err := r.client.Status().Update(ctx, freshObj); err != nil { + return nil, err + } + + return freshObj, nil +} diff --git a/vendor/github.com/knative/eventing-sources/pkg/controller/sdk/status_accessor.go b/vendor/github.com/knative/eventing-sources/pkg/controller/sdk/status_accessor.go new file mode 100644 index 00000000000..f5aa7c2c18a --- /dev/null +++ b/vendor/github.com/knative/eventing-sources/pkg/controller/sdk/status_accessor.go @@ -0,0 +1,77 @@ +/* +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 sdk + +import ( + "errors" + "fmt" + "reflect" +) + +// StatusAccessor is the interface for a Resource that implements the getter and +// setter for accessing a Condition collection. +// +k8s:deepcopy-gen=true +type StatusAccessor interface { + GetStatus() interface{} + SetStatus(interface{}) +} + +// NewReflectedStatusAccessor uses reflection to return a StatusAccessor +// to access the field called "Status". +func NewReflectedStatusAccessor(object interface{}) (StatusAccessor, error) { + objectValue := reflect.Indirect(reflect.ValueOf(object)) + + // If object is not a struct, don't even try to use it. + if objectValue.Kind() != reflect.Struct { + return nil, errors.New("object is not a struct") + } + + statusField := objectValue.FieldByName("Status") + + if statusField.IsValid() && statusField.CanInterface() && statusField.CanSet() { + if _, ok := statusField.Interface().(interface{}); ok { + return &reflectedStatusAccessor{ + status: statusField, + }, nil + } + } + return nil, fmt.Errorf("status was not an interface: %v", statusField.Kind()) +} + +// reflectedConditionsAccessor is an internal wrapper object to act as the +// ConditionsAccessor for status objects that do not implement ConditionsAccessor +// directly, but do expose the field using the "Conditions" field name. +type reflectedStatusAccessor struct { + status reflect.Value +} + +// GetConditions uses reflection to return Conditions from the held status object. +func (r *reflectedStatusAccessor) GetStatus() interface{} { + if r != nil && r.status.IsValid() && r.status.CanInterface() { + if status, ok := r.status.Interface().(interface{}); ok { + return status + } + } + return nil +} + +// SetConditions uses reflection to set Conditions on the held status object. +func (r *reflectedStatusAccessor) SetStatus(status interface{}) { + if r != nil && r.status.IsValid() && r.status.CanSet() { + r.status.Set(reflect.ValueOf(status)) + } +} diff --git a/vendor/github.com/knative/eventing-sources/pkg/controller/sinks/sinks.go b/vendor/github.com/knative/eventing-sources/pkg/controller/sinks/sinks.go new file mode 100644 index 00000000000..4e87c3ac013 --- /dev/null +++ b/vendor/github.com/knative/eventing-sources/pkg/controller/sinks/sinks.go @@ -0,0 +1,61 @@ +/* +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 sinks + +import ( + "context" + "fmt" + + "github.com/knative/pkg/apis/duck" + duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +// GetSinkURI retrieves the sink URI from the object referenced by the given +// ObjectReference. +func GetSinkURI(ctx context.Context, c client.Client, sink *corev1.ObjectReference, namespace string) (string, error) { + if sink == nil { + return "", fmt.Errorf("sink ref is nil") + } + + u := &unstructured.Unstructured{} + u.SetGroupVersionKind(sink.GroupVersionKind()) + err := c.Get(ctx, client.ObjectKey{Namespace: namespace, Name: sink.Name}, u) + if err != nil { + return "", err + } + + objIdentifier := fmt.Sprintf("\"%s/%s\" (%s)", u.GetNamespace(), u.GetName(), u.GroupVersionKind()) + + t := duckv1alpha1.AddressableType{} + err = duck.FromUnstructured(u, &t) + if err != nil { + return "", fmt.Errorf("failed to deserialize sink %s: %v", objIdentifier, err) + } + + if t.Status.Address == nil { + return "", fmt.Errorf("sink %s does not contain address", objIdentifier) + } + + if t.Status.Address.Hostname == "" { + return "", fmt.Errorf("sink %s contains an empty hostname", objIdentifier) + } + + return fmt.Sprintf("http://%s/", t.Status.Address.Hostname), nil +} diff --git a/vendor/github.com/knative/eventing-sources/pkg/controller/testing/mock_client.go b/vendor/github.com/knative/eventing-sources/pkg/controller/testing/mock_client.go new file mode 100644 index 00000000000..056199bc2d4 --- /dev/null +++ b/vendor/github.com/knative/eventing-sources/pkg/controller/testing/mock_client.go @@ -0,0 +1,153 @@ +/* +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 testing + +import ( + "context" + + "k8s.io/apimachinery/pkg/runtime" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +type MockHandled int + +const ( + // This mock has handled the function call, no further mocks nor the real client should be + // called. + Handled MockHandled = iota + // This mock has not handled the function call, subsequent mocks or the real client should be + // called. + Unhandled +) + +// All of the funcions in client.Client get mocked equivalents. For the function +// client.Client.Foo(), the mocked equivalent will be: +// func(innerClient client.Client[, arguments to Foo()]) (MockHandled[, returns from Foo()]) + +type MockGet func(innerClient client.Client, ctx context.Context, key client.ObjectKey, obj runtime.Object) (MockHandled, error) +type MockList func(innerClient client.Client, ctx context.Context, opts *client.ListOptions, list runtime.Object) (MockHandled, error) +type MockCreate func(innerClient client.Client, ctx context.Context, obj runtime.Object) (MockHandled, error) +type MockDelete func(innerClient client.Client, ctx context.Context, obj runtime.Object) (MockHandled, error) +type MockUpdate func(innerClient client.Client, ctx context.Context, obj runtime.Object) (MockHandled, error) + +var _ client.Client = (*MockClient)(nil) + +// mockClient is a client.Client that allows mock responses to be returned, instead of calling the +// inner client.Client. +type MockClient struct { + innerClient client.Client + mocks Mocks +} + +// The mocks to run on each function type. Each function will run through the mocks in its list +// until one responds with 'Handled'. If there is more than one mock in the list, then the one that +// responds 'Handled' will be removed and not run on subsequent calls to the function. If no mocks +// respond 'Handled', then the real underlying client is called. +type Mocks struct { + MockGets []MockGet + MockLists []MockList + MockCreates []MockCreate + MockDeletes []MockDelete + MockUpdates []MockUpdate +} + +func NewMockClient(innerClient client.Client, mocks Mocks) *MockClient { + return &MockClient{ + innerClient: innerClient, + mocks: mocks, + } +} + +func (m *MockClient) stopMocking() { + m.mocks = Mocks{} +} + +// All of the functions are handled almost identically: +// 1. Run through the mocks in order: +// a. If the mock handled the request, then: +// i. If there is at least one other mock in the list, remove this mock. +// ii. Return the response from the mock. +// 2. No mock handled the request, so call the inner client. + +func (m *MockClient) Get(ctx context.Context, key client.ObjectKey, obj runtime.Object) error { + for i, mockGet := range m.mocks.MockGets { + handled, err := mockGet(m.innerClient, ctx, key, obj) + if handled == Handled { + if len(m.mocks.MockGets) > 1 { + m.mocks.MockGets = append(m.mocks.MockGets[:i], m.mocks.MockGets[i+1:]...) + } + return err + } + } + return m.innerClient.Get(ctx, key, obj) +} + +func (m *MockClient) List(ctx context.Context, opts *client.ListOptions, list runtime.Object) error { + for i, mockList := range m.mocks.MockLists { + handled, err := mockList(m.innerClient, ctx, opts, list) + if handled == Handled { + if len(m.mocks.MockLists) > 1 { + m.mocks.MockLists = append(m.mocks.MockLists[:i], m.mocks.MockLists[i+1:]...) + } + return err + } + } + return m.innerClient.List(ctx, opts, list) +} + +func (m *MockClient) Create(ctx context.Context, obj runtime.Object) error { + for i, mockCreate := range m.mocks.MockCreates { + handled, err := mockCreate(m.innerClient, ctx, obj) + if handled == Handled { + if len(m.mocks.MockCreates) > 1 { + m.mocks.MockCreates = append(m.mocks.MockCreates[:i], m.mocks.MockCreates[i+1:]...) + } + return err + } + } + return m.innerClient.Create(ctx, obj) +} + +func (m *MockClient) Delete(ctx context.Context, obj runtime.Object, opts ...client.DeleteOptionFunc) error { + for i, mockDelete := range m.mocks.MockDeletes { + handled, err := mockDelete(m.innerClient, ctx, obj) + if handled == Handled { + if len(m.mocks.MockDeletes) > 1 { + m.mocks.MockDeletes = append(m.mocks.MockDeletes[:i], m.mocks.MockDeletes[i+1:]...) + } + return err + } + } + return m.innerClient.Delete(ctx, obj, opts...) +} + +func (m *MockClient) Update(ctx context.Context, obj runtime.Object) error { + for i, mockUpdate := range m.mocks.MockUpdates { + handled, err := mockUpdate(m.innerClient, ctx, obj) + if handled == Handled { + if len(m.mocks.MockUpdates) > 1 { + m.mocks.MockUpdates = append(m.mocks.MockUpdates[:i], m.mocks.MockUpdates[i+1:]...) + } + return err + } + } + return m.innerClient.Update(ctx, obj) +} + +func (m *MockClient) Status() client.StatusWriter { + return m.innerClient.Status() +} diff --git a/vendor/github.com/knative/eventing-sources/pkg/controller/testing/table.go b/vendor/github.com/knative/eventing-sources/pkg/controller/testing/table.go new file mode 100644 index 00000000000..bb23d668bf8 --- /dev/null +++ b/vendor/github.com/knative/eventing-sources/pkg/controller/testing/table.go @@ -0,0 +1,275 @@ +/* +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 testing + +import ( + "context" + "fmt" + "strings" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + "github.com/knative/eventing-sources/pkg/controller/sdk" + "github.com/knative/pkg/apis" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/dynamic" + dynamicfake "k8s.io/client-go/dynamic/fake" + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/tools/cache" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + "sigs.k8s.io/controller-runtime/pkg/reconcile" +) + +// TestCase holds a single row of our table test. +type TestCase struct { + // Name is a descriptive name for this test suitable as a first argument to t.Run() + Name string + + // InitialState is the list of objects that already exists when reconciliation + // starts. + InitialState []runtime.Object + + Reconciles runtime.Object + + // ReconcileKey is the key of the object to reconcile in namespace/name form. + ReconcileKey string + + // WantErr is true when we expect the Reconcile function to return an error. + WantErr bool + + // WantErrMsg contains the pattern to match the returned error message. + // Implies WantErr = true. + WantErrMsg string + + // WantResult is the reconcile result we expect to be returned from the + // Reconcile function. + WantResult reconcile.Result + + // WantResultObject is the reconcile result we expect to be returned from the + // Reconcile function. + WantResultObject runtime.Object + + // WantPresent holds the non-exclusive set of objects we expect to exist + // after reconciliation completes. + WantPresent []runtime.Object + + // WantAbsent holds the list of objects expected to not exist + // after reconciliation completes. + WantAbsent []runtime.Object + + // Mocks that tamper with the client's responses. + Mocks Mocks + + // Scheme for the dynamic client + Scheme *runtime.Scheme + + // Fake dynamic objects + Objects []runtime.Object + + // OtherTestData is arbitrary data needed for the test. It is not used directly by the table + // testing framework. Instead it is used in the test method. E.g. setting up the responses for a + // fake GCP PubSub client can go in here, as no other field makes sense for it. + OtherTestData map[string]interface{} + + // IgnoreTimes causes comparisons to ignore fields of type apis.VolatileTime. + IgnoreTimes bool +} + +// Runner returns a testing func that can be passed to t.Run. +func (tc *TestCase) Runner(t *testing.T, r sdk.KnativeReconciler, c *MockClient) func(t *testing.T) { + return func(t *testing.T) { + result, recErr := tc.Reconcile(c, r) + + if err := tc.VerifyErr(recErr); err != nil { + t.Error(err) + } + + // Push back the reconciled changes into the client. + if result != nil { + c.Update(context.TODO(), result) + } + + // Verifying should be done against the innerClient, never against mocks. + c.stopMocking() + + if err := tc.VerifyWantPresent(c); err != nil { + t.Error(err) + } + + if err := tc.VerifyWantAbsent(c); err != nil { + t.Error(err) + } + } +} + +// GetDynamicClient returns the mockDynamicClient to use for this test case. +func (tc *TestCase) GetDynamicClient() dynamic.Interface { + if tc.Scheme == nil { + return dynamicfake.NewSimpleDynamicClient(runtime.NewScheme(), tc.Objects...) + } + return dynamicfake.NewSimpleDynamicClient(tc.Scheme, tc.Objects...) +} + +// GetClient returns the mockClient to use for this test case. +func (tc *TestCase) GetClient() *MockClient { + innerClient := fake.NewFakeClient(tc.InitialState...) + return NewMockClient(innerClient, tc.Mocks) +} + +// Reconcile calls the given reconciler's Reconcile() function with the test +// case's reconcile request. +func (tc *TestCase) Reconcile(c client.Client, r sdk.KnativeReconciler) (runtime.Object, error) { + if tc.ReconcileKey == "" { + return nil, fmt.Errorf("test did not set ReconcileKey") + } + ns, n, err := cache.SplitMetaNamespaceKey(tc.ReconcileKey) + if err != nil { + return nil, err + } + + obj := tc.Reconciles.DeepCopyObject() + err = c.Get(context.TODO(), client.ObjectKey{Namespace: ns, Name: n}, obj) + if err != nil { + // Not found is not an error. + return nil, nil + } + + return obj, r.Reconcile(context.TODO(), obj) +} + +// VerifyErr verifies that the given error returned from Reconcile is the error +// expected by the test case. +func (tc *TestCase) VerifyErr(err error) error { + // A non-empty WantErrMsg implies that an error is wanted. + wantErr := tc.WantErr || tc.WantErrMsg != "" + + if wantErr && err == nil { + return fmt.Errorf("want error, got nil") + } + + if !wantErr && err != nil { + return fmt.Errorf("want no error, got %v", err) + } + + if err != nil { + if diff := cmp.Diff(tc.WantErrMsg, err.Error()); diff != "" { + return fmt.Errorf("incorrect error (-want, +got): %v", diff) + } + } + return nil +} + +// VerifyResult verifies that the given result returned from Reconcile is the +// result expected by the test case. +func (tc *TestCase) VerifyResult(result reconcile.Result) error { + if diff := cmp.Diff(tc.WantResult, result); diff != "" { + return fmt.Errorf("unexpected reconcile Result (-want +got) %v", diff) + } + return nil +} + +// VerifyResult verifies that the given result returned from Reconcile is the +// result expected by the test case. +func (tc *TestCase) VerifyResultSDK(result runtime.Object) error { + if diff := cmp.Diff(tc.WantResultObject, result); diff != "" { + return fmt.Errorf("unexpected reconcile Result Object (-want +got) %v", diff) + } + return nil +} + +type stateErrors struct { + errors []error +} + +func (se stateErrors) Error() string { + msgs := make([]string, 0) + for _, err := range se.errors { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "\n") +} + +// VerifyWantPresent verifies that the client contains all the objects expected +// to be present after reconciliation. +func (tc *TestCase) VerifyWantPresent(c client.Client) error { + var errs stateErrors + for _, wp := range tc.WantPresent { + o, err := scheme.Scheme.New(wp.GetObjectKind().GroupVersionKind()) + if err != nil { + errs.errors = append(errs.errors, fmt.Errorf("error creating a copy of %T: %v", wp, err)) + } + acc, err := meta.Accessor(wp) + if err != nil { + errs.errors = append(errs.errors, fmt.Errorf("error getting accessor for %#v %v", wp, err)) + } + err = c.Get(context.TODO(), client.ObjectKey{Namespace: acc.GetNamespace(), Name: acc.GetName()}, o) + if err != nil { + if apierrors.IsNotFound(err) { + errs.errors = append(errs.errors, fmt.Errorf("want present %T %s/%s, got absent", wp, acc.GetNamespace(), acc.GetName())) + } else { + errs.errors = append(errs.errors, fmt.Errorf("error getting %T %s/%s: %v", wp, acc.GetNamespace(), acc.GetName(), err)) + } + } + + diffOpts := cmp.Options{ + // Ignore TypeMeta, since the objects created by the controller won't have + // it + cmpopts.IgnoreTypes(metav1.TypeMeta{}), + } + + if tc.IgnoreTimes { + // Ignore VolatileTime fields, since they rarely compare correctly. + diffOpts = append(diffOpts, cmpopts.IgnoreTypes(apis.VolatileTime{})) + } + + if diff := cmp.Diff(wp, o, diffOpts...); diff != "" { + errs.errors = append(errs.errors, fmt.Errorf("Unexpected present %T %s/%s (-want +got):\n%v", wp, acc.GetNamespace(), acc.GetName(), diff)) + } + } + if len(errs.errors) > 0 { + return errs + } + return nil +} + +// VerifyWantAbsent verifies that the client does not contain any of the objects +// expected to be absent after reconciliation. +func (tc *TestCase) VerifyWantAbsent(c client.Client) error { + var errs stateErrors + for _, wa := range tc.WantAbsent { + acc, err := meta.Accessor(wa) + if err != nil { + errs.errors = append(errs.errors, fmt.Errorf("error getting accessor for %#v %v", wa, err)) + } + err = c.Get(context.TODO(), client.ObjectKey{Namespace: acc.GetNamespace(), Name: acc.GetName()}, wa) + if err == nil { + errs.errors = append(errs.errors, fmt.Errorf("want absent, got present %T %s/%s", wa, acc.GetNamespace(), acc.GetName())) + } + if !apierrors.IsNotFound(err) { + errs.errors = append(errs.errors, fmt.Errorf("error getting %T %s/%s: %v", wa, acc.GetNamespace(), acc.GetName(), err)) + } + } + if len(errs.errors) > 0 { + return errs + } + return nil +} diff --git a/vendor/github.com/knative/eventing-sources/pkg/kncloudevents/good_client.go b/vendor/github.com/knative/eventing-sources/pkg/kncloudevents/good_client.go new file mode 100644 index 00000000000..52384cc889e --- /dev/null +++ b/vendor/github.com/knative/eventing-sources/pkg/kncloudevents/good_client.go @@ -0,0 +1,28 @@ +package kncloudevents + +import ( + "github.com/cloudevents/sdk-go/pkg/cloudevents/client" + "github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http" +) + +func NewDefaultClient(target ...string) (client.Client, error) { + tOpts := []http.Option{http.WithBinaryEncoding()} + if len(target) > 0 && target[0] != "" { + tOpts = append(tOpts, http.WithTarget(target[0])) + } + + // Make an http transport for the CloudEvents client. + t, err := http.New(tOpts...) + if err != nil { + return nil, err + } + // Use the transport to make a new CloudEvents client. + c, err := client.New(t, + client.WithUUIDs(), + client.WithTimeNow(), + ) + if err != nil { + return nil, err + } + return c, nil +} diff --git a/vendor/github.com/knative/eventing-sources/pkg/reconciler/containersource/resources/arguments.go b/vendor/github.com/knative/eventing-sources/pkg/reconciler/containersource/resources/arguments.go new file mode 100644 index 00000000000..9eb2884f4f7 --- /dev/null +++ b/vendor/github.com/knative/eventing-sources/pkg/reconciler/containersource/resources/arguments.go @@ -0,0 +1,34 @@ +/* +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 ( + corev1 "k8s.io/api/core/v1" +) + +type ContainerArguments struct { + Name string + Namespace string + Image string + Args []string + Env []corev1.EnvVar + ServiceAccountName string + SinkInArgs bool + Sink string + Annotations map[string]string + Labels map[string]string +} diff --git a/vendor/github.com/knative/eventing-sources/pkg/reconciler/containersource/resources/deployment.go b/vendor/github.com/knative/eventing-sources/pkg/reconciler/containersource/resources/deployment.go new file mode 100644 index 00000000000..2e253dc3531 --- /dev/null +++ b/vendor/github.com/knative/eventing-sources/pkg/reconciler/containersource/resources/deployment.go @@ -0,0 +1,115 @@ +/* +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" + "strings" + + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +const sourceLabelKey = "eventing.knative.dev/source" + +func MakeDeployment(org *appsv1.Deployment, args *ContainerArguments) *appsv1.Deployment { + + containerArgs := []string(nil) + if args != nil { + containerArgs = args.Args + } + // if sink is already in the provided args.Args, don't attempt to add + if !args.SinkInArgs { + remote := fmt.Sprintf("--sink=%s", args.Sink) + containerArgs = append(containerArgs, remote) + } + + env := append(args.Env, corev1.EnvVar{Name: "SINK", Value: sinkArg(args)}) + + deploy := &appsv1.Deployment{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "apps/v1", + Kind: "Deployment", + }, + ObjectMeta: metav1.ObjectMeta{ + GenerateName: args.Name + "-", + Namespace: args.Namespace, + }, + Spec: appsv1.DeploymentSpec{ + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + sourceLabelKey: args.Name, + }, + }, + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + "sidecar.istio.io/inject": "true", + }, + Labels: map[string]string{ + sourceLabelKey: args.Name, + }, + }, + Spec: corev1.PodSpec{ + ServiceAccountName: args.ServiceAccountName, + Containers: []corev1.Container{ + { + Name: "source", + Image: args.Image, + Args: containerArgs, + Env: env, + ImagePullPolicy: corev1.PullIfNotPresent, + }, + }, + }, + }, + }, + } + + // Then wire through any annotations from the source. Not a bug by allowing + // the container to override Istio injection. + if args.Annotations != nil { + for k, v := range args.Annotations { + deploy.Spec.Template.ObjectMeta.Annotations[k] = v + } + } + + // Then wire through any labels from the source. Do not allow to override + // our source name. This seems like it would be way errorprone by allowing + // the matchlabels then to not match, or we'd have to force them to match, etc. + // just don't allow it. + if args.Labels != nil { + for k, v := range args.Labels { + if k != sourceLabelKey { + deploy.Spec.Template.ObjectMeta.Labels[k] = v + } + } + } + return deploy +} + +func sinkArg(args *ContainerArguments) string { + if args.SinkInArgs { + for _, a := range args.Args { + if strings.HasPrefix(a, "--sink=") { + return strings.Replace(a, "--sink=", "", -1) + } + } + } + return args.Sink +} diff --git a/vendor/github.com/knative/eventing-sources/test/test_images/k8sevents/kodata/LICENSE b/vendor/github.com/knative/eventing-sources/test/test_images/k8sevents/kodata/LICENSE new file mode 120000 index 00000000000..14776154326 --- /dev/null +++ b/vendor/github.com/knative/eventing-sources/test/test_images/k8sevents/kodata/LICENSE @@ -0,0 +1 @@ +../../../../LICENSE \ No newline at end of file diff --git a/vendor/github.com/knative/eventing-sources/test/test_images/k8sevents/kodata/VENDOR-LICENSE b/vendor/github.com/knative/eventing-sources/test/test_images/k8sevents/kodata/VENDOR-LICENSE new file mode 120000 index 00000000000..7322c09d957 --- /dev/null +++ b/vendor/github.com/knative/eventing-sources/test/test_images/k8sevents/kodata/VENDOR-LICENSE @@ -0,0 +1 @@ +../../../../third_party/VENDOR-LICENSE \ No newline at end of file diff --git a/vendor/github.com/robfig/cron/LICENSE b/vendor/github.com/robfig/cron/LICENSE new file mode 100644 index 00000000000..3a0f627ffeb --- /dev/null +++ b/vendor/github.com/robfig/cron/LICENSE @@ -0,0 +1,21 @@ +Copyright (C) 2012 Rob Figueiredo +All Rights Reserved. + +MIT LICENSE + +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/robfig/cron/constantdelay.go b/vendor/github.com/robfig/cron/constantdelay.go new file mode 100644 index 00000000000..cd6e7b1be91 --- /dev/null +++ b/vendor/github.com/robfig/cron/constantdelay.go @@ -0,0 +1,27 @@ +package cron + +import "time" + +// ConstantDelaySchedule represents a simple recurring duty cycle, e.g. "Every 5 minutes". +// It does not support jobs more frequent than once a second. +type ConstantDelaySchedule struct { + Delay time.Duration +} + +// Every returns a crontab Schedule that activates once every duration. +// Delays of less than a second are not supported (will round up to 1 second). +// Any fields less than a Second are truncated. +func Every(duration time.Duration) ConstantDelaySchedule { + if duration < time.Second { + duration = time.Second + } + return ConstantDelaySchedule{ + Delay: duration - time.Duration(duration.Nanoseconds())%time.Second, + } +} + +// Next returns the next time this should be run. +// This rounds so that the next activation time will be on the second. +func (schedule ConstantDelaySchedule) Next(t time.Time) time.Time { + return t.Add(schedule.Delay - time.Duration(t.Nanosecond())*time.Nanosecond) +} diff --git a/vendor/github.com/robfig/cron/cron.go b/vendor/github.com/robfig/cron/cron.go new file mode 100644 index 00000000000..2318aeb2e7d --- /dev/null +++ b/vendor/github.com/robfig/cron/cron.go @@ -0,0 +1,259 @@ +package cron + +import ( + "log" + "runtime" + "sort" + "time" +) + +// Cron keeps track of any number of entries, invoking the associated func as +// specified by the schedule. It may be started, stopped, and the entries may +// be inspected while running. +type Cron struct { + entries []*Entry + stop chan struct{} + add chan *Entry + snapshot chan []*Entry + running bool + ErrorLog *log.Logger + location *time.Location +} + +// Job is an interface for submitted cron jobs. +type Job interface { + Run() +} + +// The Schedule describes a job's duty cycle. +type Schedule interface { + // Return the next activation time, later than the given time. + // Next is invoked initially, and then each time the job is run. + Next(time.Time) time.Time +} + +// Entry consists of a schedule and the func to execute on that schedule. +type Entry struct { + // The schedule on which this job should be run. + Schedule Schedule + + // The next time the job will run. This is the zero time if Cron has not been + // started or this entry's schedule is unsatisfiable + Next time.Time + + // The last time this job was run. This is the zero time if the job has never + // been run. + Prev time.Time + + // The Job to run. + Job Job +} + +// byTime is a wrapper for sorting the entry array by time +// (with zero time at the end). +type byTime []*Entry + +func (s byTime) Len() int { return len(s) } +func (s byTime) Swap(i, j int) { s[i], s[j] = s[j], s[i] } +func (s byTime) Less(i, j int) bool { + // Two zero times should return false. + // Otherwise, zero is "greater" than any other time. + // (To sort it at the end of the list.) + if s[i].Next.IsZero() { + return false + } + if s[j].Next.IsZero() { + return true + } + return s[i].Next.Before(s[j].Next) +} + +// New returns a new Cron job runner, in the Local time zone. +func New() *Cron { + return NewWithLocation(time.Now().Location()) +} + +// NewWithLocation returns a new Cron job runner. +func NewWithLocation(location *time.Location) *Cron { + return &Cron{ + entries: nil, + add: make(chan *Entry), + stop: make(chan struct{}), + snapshot: make(chan []*Entry), + running: false, + ErrorLog: nil, + location: location, + } +} + +// A wrapper that turns a func() into a cron.Job +type FuncJob func() + +func (f FuncJob) Run() { f() } + +// AddFunc adds a func to the Cron to be run on the given schedule. +func (c *Cron) AddFunc(spec string, cmd func()) error { + return c.AddJob(spec, FuncJob(cmd)) +} + +// AddJob adds a Job to the Cron to be run on the given schedule. +func (c *Cron) AddJob(spec string, cmd Job) error { + schedule, err := Parse(spec) + if err != nil { + return err + } + c.Schedule(schedule, cmd) + return nil +} + +// Schedule adds a Job to the Cron to be run on the given schedule. +func (c *Cron) Schedule(schedule Schedule, cmd Job) { + entry := &Entry{ + Schedule: schedule, + Job: cmd, + } + if !c.running { + c.entries = append(c.entries, entry) + return + } + + c.add <- entry +} + +// Entries returns a snapshot of the cron entries. +func (c *Cron) Entries() []*Entry { + if c.running { + c.snapshot <- nil + x := <-c.snapshot + return x + } + return c.entrySnapshot() +} + +// Location gets the time zone location +func (c *Cron) Location() *time.Location { + return c.location +} + +// Start the cron scheduler in its own go-routine, or no-op if already started. +func (c *Cron) Start() { + if c.running { + return + } + c.running = true + go c.run() +} + +// Run the cron scheduler, or no-op if already running. +func (c *Cron) Run() { + if c.running { + return + } + c.running = true + c.run() +} + +func (c *Cron) runWithRecovery(j Job) { + defer func() { + if r := recover(); r != nil { + const size = 64 << 10 + buf := make([]byte, size) + buf = buf[:runtime.Stack(buf, false)] + c.logf("cron: panic running job: %v\n%s", r, buf) + } + }() + j.Run() +} + +// Run the scheduler. this is private just due to the need to synchronize +// access to the 'running' state variable. +func (c *Cron) run() { + // Figure out the next activation times for each entry. + now := c.now() + for _, entry := range c.entries { + entry.Next = entry.Schedule.Next(now) + } + + for { + // Determine the next entry to run. + sort.Sort(byTime(c.entries)) + + var timer *time.Timer + if len(c.entries) == 0 || c.entries[0].Next.IsZero() { + // If there are no entries yet, just sleep - it still handles new entries + // and stop requests. + timer = time.NewTimer(100000 * time.Hour) + } else { + timer = time.NewTimer(c.entries[0].Next.Sub(now)) + } + + for { + select { + case now = <-timer.C: + now = now.In(c.location) + // Run every entry whose next time was less than now + for _, e := range c.entries { + if e.Next.After(now) || e.Next.IsZero() { + break + } + go c.runWithRecovery(e.Job) + e.Prev = e.Next + e.Next = e.Schedule.Next(now) + } + + case newEntry := <-c.add: + timer.Stop() + now = c.now() + newEntry.Next = newEntry.Schedule.Next(now) + c.entries = append(c.entries, newEntry) + + case <-c.snapshot: + c.snapshot <- c.entrySnapshot() + continue + + case <-c.stop: + timer.Stop() + return + } + + break + } + } +} + +// Logs an error to stderr or to the configured error log +func (c *Cron) logf(format string, args ...interface{}) { + if c.ErrorLog != nil { + c.ErrorLog.Printf(format, args...) + } else { + log.Printf(format, args...) + } +} + +// Stop stops the cron scheduler if it is running; otherwise it does nothing. +func (c *Cron) Stop() { + if !c.running { + return + } + c.stop <- struct{}{} + c.running = false +} + +// entrySnapshot returns a copy of the current cron entry list. +func (c *Cron) entrySnapshot() []*Entry { + entries := []*Entry{} + for _, e := range c.entries { + entries = append(entries, &Entry{ + Schedule: e.Schedule, + Next: e.Next, + Prev: e.Prev, + Job: e.Job, + }) + } + return entries +} + +// now returns current time in c location +func (c *Cron) now() time.Time { + return time.Now().In(c.location) +} diff --git a/vendor/github.com/robfig/cron/doc.go b/vendor/github.com/robfig/cron/doc.go new file mode 100644 index 00000000000..d02ec2f3b56 --- /dev/null +++ b/vendor/github.com/robfig/cron/doc.go @@ -0,0 +1,129 @@ +/* +Package cron implements a cron spec parser and job runner. + +Usage + +Callers may register Funcs to be invoked on a given schedule. Cron will run +them in their own goroutines. + + c := cron.New() + c.AddFunc("0 30 * * * *", func() { fmt.Println("Every hour on the half hour") }) + c.AddFunc("@hourly", func() { fmt.Println("Every hour") }) + c.AddFunc("@every 1h30m", func() { fmt.Println("Every hour thirty") }) + c.Start() + .. + // Funcs are invoked in their own goroutine, asynchronously. + ... + // Funcs may also be added to a running Cron + c.AddFunc("@daily", func() { fmt.Println("Every day") }) + .. + // Inspect the cron job entries' next and previous run times. + inspect(c.Entries()) + .. + c.Stop() // Stop the scheduler (does not stop any jobs already running). + +CRON Expression Format + +A cron expression represents a set of times, using 6 space-separated fields. + + Field name | Mandatory? | Allowed values | Allowed special characters + ---------- | ---------- | -------------- | -------------------------- + Seconds | Yes | 0-59 | * / , - + Minutes | Yes | 0-59 | * / , - + Hours | Yes | 0-23 | * / , - + Day of month | Yes | 1-31 | * / , - ? + Month | Yes | 1-12 or JAN-DEC | * / , - + Day of week | Yes | 0-6 or SUN-SAT | * / , - ? + +Note: Month and Day-of-week field values are case insensitive. "SUN", "Sun", +and "sun" are equally accepted. + +Special Characters + +Asterisk ( * ) + +The asterisk indicates that the cron expression will match for all values of the +field; e.g., using an asterisk in the 5th field (month) would indicate every +month. + +Slash ( / ) + +Slashes are used to describe increments of ranges. For example 3-59/15 in the +1st field (minutes) would indicate the 3rd minute of the hour and every 15 +minutes thereafter. The form "*\/..." is equivalent to the form "first-last/...", +that is, an increment over the largest possible range of the field. The form +"N/..." is accepted as meaning "N-MAX/...", that is, starting at N, use the +increment until the end of that specific range. It does not wrap around. + +Comma ( , ) + +Commas are used to separate items of a list. For example, using "MON,WED,FRI" in +the 5th field (day of week) would mean Mondays, Wednesdays and Fridays. + +Hyphen ( - ) + +Hyphens are used to define ranges. For example, 9-17 would indicate every +hour between 9am and 5pm inclusive. + +Question mark ( ? ) + +Question mark may be used instead of '*' for leaving either day-of-month or +day-of-week blank. + +Predefined schedules + +You may use one of several pre-defined schedules in place of a cron expression. + + Entry | Description | Equivalent To + ----- | ----------- | ------------- + @yearly (or @annually) | Run once a year, midnight, Jan. 1st | 0 0 0 1 1 * + @monthly | Run once a month, midnight, first of month | 0 0 0 1 * * + @weekly | Run once a week, midnight between Sat/Sun | 0 0 0 * * 0 + @daily (or @midnight) | Run once a day, midnight | 0 0 0 * * * + @hourly | Run once an hour, beginning of hour | 0 0 * * * * + +Intervals + +You may also schedule a job to execute at fixed intervals, starting at the time it's added +or cron is run. This is supported by formatting the cron spec like this: + + @every + +where "duration" is a string accepted by time.ParseDuration +(http://golang.org/pkg/time/#ParseDuration). + +For example, "@every 1h30m10s" would indicate a schedule that activates after +1 hour, 30 minutes, 10 seconds, and then every interval after that. + +Note: The interval does not take the job runtime into account. For example, +if a job takes 3 minutes to run, and it is scheduled to run every 5 minutes, +it will have only 2 minutes of idle time between each run. + +Time zones + +All interpretation and scheduling is done in the machine's local time zone (as +provided by the Go time package (http://www.golang.org/pkg/time). + +Be aware that jobs scheduled during daylight-savings leap-ahead transitions will +not be run! + +Thread safety + +Since the Cron service runs concurrently with the calling code, some amount of +care must be taken to ensure proper synchronization. + +All cron methods are designed to be correctly synchronized as long as the caller +ensures that invocations have a clear happens-before ordering between them. + +Implementation + +Cron entries are stored in an array, sorted by their next activation time. Cron +sleeps until the next job is due to be run. + +Upon waking: + - it runs each entry that is active on that second + - it calculates the next run times for the jobs that were run + - it re-sorts the array of entries by next activation time. + - it goes to sleep until the soonest job. +*/ +package cron diff --git a/vendor/github.com/robfig/cron/parser.go b/vendor/github.com/robfig/cron/parser.go new file mode 100644 index 00000000000..a5e83c0a8dc --- /dev/null +++ b/vendor/github.com/robfig/cron/parser.go @@ -0,0 +1,380 @@ +package cron + +import ( + "fmt" + "math" + "strconv" + "strings" + "time" +) + +// Configuration options for creating a parser. Most options specify which +// fields should be included, while others enable features. If a field is not +// included the parser will assume a default value. These options do not change +// the order fields are parse in. +type ParseOption int + +const ( + Second ParseOption = 1 << iota // Seconds field, default 0 + Minute // Minutes field, default 0 + Hour // Hours field, default 0 + Dom // Day of month field, default * + Month // Month field, default * + Dow // Day of week field, default * + DowOptional // Optional day of week field, default * + Descriptor // Allow descriptors such as @monthly, @weekly, etc. +) + +var places = []ParseOption{ + Second, + Minute, + Hour, + Dom, + Month, + Dow, +} + +var defaults = []string{ + "0", + "0", + "0", + "*", + "*", + "*", +} + +// A custom Parser that can be configured. +type Parser struct { + options ParseOption + optionals int +} + +// Creates a custom Parser with custom options. +// +// // Standard parser without descriptors +// specParser := NewParser(Minute | Hour | Dom | Month | Dow) +// sched, err := specParser.Parse("0 0 15 */3 *") +// +// // Same as above, just excludes time fields +// subsParser := NewParser(Dom | Month | Dow) +// sched, err := specParser.Parse("15 */3 *") +// +// // Same as above, just makes Dow optional +// subsParser := NewParser(Dom | Month | DowOptional) +// sched, err := specParser.Parse("15 */3") +// +func NewParser(options ParseOption) Parser { + optionals := 0 + if options&DowOptional > 0 { + options |= Dow + optionals++ + } + return Parser{options, optionals} +} + +// Parse returns a new crontab schedule representing the given spec. +// It returns a descriptive error if the spec is not valid. +// It accepts crontab specs and features configured by NewParser. +func (p Parser) Parse(spec string) (Schedule, error) { + if len(spec) == 0 { + return nil, fmt.Errorf("Empty spec string") + } + if spec[0] == '@' && p.options&Descriptor > 0 { + return parseDescriptor(spec) + } + + // Figure out how many fields we need + max := 0 + for _, place := range places { + if p.options&place > 0 { + max++ + } + } + min := max - p.optionals + + // Split fields on whitespace + fields := strings.Fields(spec) + + // Validate number of fields + if count := len(fields); count < min || count > max { + if min == max { + return nil, fmt.Errorf("Expected exactly %d fields, found %d: %s", min, count, spec) + } + return nil, fmt.Errorf("Expected %d to %d fields, found %d: %s", min, max, count, spec) + } + + // Fill in missing fields + fields = expandFields(fields, p.options) + + var err error + field := func(field string, r bounds) uint64 { + if err != nil { + return 0 + } + var bits uint64 + bits, err = getField(field, r) + return bits + } + + var ( + second = field(fields[0], seconds) + minute = field(fields[1], minutes) + hour = field(fields[2], hours) + dayofmonth = field(fields[3], dom) + month = field(fields[4], months) + dayofweek = field(fields[5], dow) + ) + if err != nil { + return nil, err + } + + return &SpecSchedule{ + Second: second, + Minute: minute, + Hour: hour, + Dom: dayofmonth, + Month: month, + Dow: dayofweek, + }, nil +} + +func expandFields(fields []string, options ParseOption) []string { + n := 0 + count := len(fields) + expFields := make([]string, len(places)) + copy(expFields, defaults) + for i, place := range places { + if options&place > 0 { + expFields[i] = fields[n] + n++ + } + if n == count { + break + } + } + return expFields +} + +var standardParser = NewParser( + Minute | Hour | Dom | Month | Dow | Descriptor, +) + +// ParseStandard returns a new crontab schedule representing the given standardSpec +// (https://en.wikipedia.org/wiki/Cron). It differs from Parse requiring to always +// pass 5 entries representing: minute, hour, day of month, month and day of week, +// in that order. It returns a descriptive error if the spec is not valid. +// +// It accepts +// - Standard crontab specs, e.g. "* * * * ?" +// - Descriptors, e.g. "@midnight", "@every 1h30m" +func ParseStandard(standardSpec string) (Schedule, error) { + return standardParser.Parse(standardSpec) +} + +var defaultParser = NewParser( + Second | Minute | Hour | Dom | Month | DowOptional | Descriptor, +) + +// Parse returns a new crontab schedule representing the given spec. +// It returns a descriptive error if the spec is not valid. +// +// It accepts +// - Full crontab specs, e.g. "* * * * * ?" +// - Descriptors, e.g. "@midnight", "@every 1h30m" +func Parse(spec string) (Schedule, error) { + return defaultParser.Parse(spec) +} + +// getField returns an Int with the bits set representing all of the times that +// the field represents or error parsing field value. A "field" is a comma-separated +// list of "ranges". +func getField(field string, r bounds) (uint64, error) { + var bits uint64 + ranges := strings.FieldsFunc(field, func(r rune) bool { return r == ',' }) + for _, expr := range ranges { + bit, err := getRange(expr, r) + if err != nil { + return bits, err + } + bits |= bit + } + return bits, nil +} + +// getRange returns the bits indicated by the given expression: +// number | number "-" number [ "/" number ] +// or error parsing range. +func getRange(expr string, r bounds) (uint64, error) { + var ( + start, end, step uint + rangeAndStep = strings.Split(expr, "/") + lowAndHigh = strings.Split(rangeAndStep[0], "-") + singleDigit = len(lowAndHigh) == 1 + err error + ) + + var extra uint64 + if lowAndHigh[0] == "*" || lowAndHigh[0] == "?" { + start = r.min + end = r.max + extra = starBit + } else { + start, err = parseIntOrName(lowAndHigh[0], r.names) + if err != nil { + return 0, err + } + switch len(lowAndHigh) { + case 1: + end = start + case 2: + end, err = parseIntOrName(lowAndHigh[1], r.names) + if err != nil { + return 0, err + } + default: + return 0, fmt.Errorf("Too many hyphens: %s", expr) + } + } + + switch len(rangeAndStep) { + case 1: + step = 1 + case 2: + step, err = mustParseInt(rangeAndStep[1]) + if err != nil { + return 0, err + } + + // Special handling: "N/step" means "N-max/step". + if singleDigit { + end = r.max + } + default: + return 0, fmt.Errorf("Too many slashes: %s", expr) + } + + if start < r.min { + return 0, fmt.Errorf("Beginning of range (%d) below minimum (%d): %s", start, r.min, expr) + } + if end > r.max { + return 0, fmt.Errorf("End of range (%d) above maximum (%d): %s", end, r.max, expr) + } + if start > end { + return 0, fmt.Errorf("Beginning of range (%d) beyond end of range (%d): %s", start, end, expr) + } + if step == 0 { + return 0, fmt.Errorf("Step of range should be a positive number: %s", expr) + } + + return getBits(start, end, step) | extra, nil +} + +// parseIntOrName returns the (possibly-named) integer contained in expr. +func parseIntOrName(expr string, names map[string]uint) (uint, error) { + if names != nil { + if namedInt, ok := names[strings.ToLower(expr)]; ok { + return namedInt, nil + } + } + return mustParseInt(expr) +} + +// mustParseInt parses the given expression as an int or returns an error. +func mustParseInt(expr string) (uint, error) { + num, err := strconv.Atoi(expr) + if err != nil { + return 0, fmt.Errorf("Failed to parse int from %s: %s", expr, err) + } + if num < 0 { + return 0, fmt.Errorf("Negative number (%d) not allowed: %s", num, expr) + } + + return uint(num), nil +} + +// getBits sets all bits in the range [min, max], modulo the given step size. +func getBits(min, max, step uint) uint64 { + var bits uint64 + + // If step is 1, use shifts. + if step == 1 { + return ^(math.MaxUint64 << (max + 1)) & (math.MaxUint64 << min) + } + + // Else, use a simple loop. + for i := min; i <= max; i += step { + bits |= 1 << i + } + return bits +} + +// all returns all bits within the given bounds. (plus the star bit) +func all(r bounds) uint64 { + return getBits(r.min, r.max, 1) | starBit +} + +// parseDescriptor returns a predefined schedule for the expression, or error if none matches. +func parseDescriptor(descriptor string) (Schedule, error) { + switch descriptor { + case "@yearly", "@annually": + return &SpecSchedule{ + Second: 1 << seconds.min, + Minute: 1 << minutes.min, + Hour: 1 << hours.min, + Dom: 1 << dom.min, + Month: 1 << months.min, + Dow: all(dow), + }, nil + + case "@monthly": + return &SpecSchedule{ + Second: 1 << seconds.min, + Minute: 1 << minutes.min, + Hour: 1 << hours.min, + Dom: 1 << dom.min, + Month: all(months), + Dow: all(dow), + }, nil + + case "@weekly": + return &SpecSchedule{ + Second: 1 << seconds.min, + Minute: 1 << minutes.min, + Hour: 1 << hours.min, + Dom: all(dom), + Month: all(months), + Dow: 1 << dow.min, + }, nil + + case "@daily", "@midnight": + return &SpecSchedule{ + Second: 1 << seconds.min, + Minute: 1 << minutes.min, + Hour: 1 << hours.min, + Dom: all(dom), + Month: all(months), + Dow: all(dow), + }, nil + + case "@hourly": + return &SpecSchedule{ + Second: 1 << seconds.min, + Minute: 1 << minutes.min, + Hour: all(hours), + Dom: all(dom), + Month: all(months), + Dow: all(dow), + }, nil + } + + const every = "@every " + if strings.HasPrefix(descriptor, every) { + duration, err := time.ParseDuration(descriptor[len(every):]) + if err != nil { + return nil, fmt.Errorf("Failed to parse duration %s: %s", descriptor, err) + } + return Every(duration), nil + } + + return nil, fmt.Errorf("Unrecognized descriptor: %s", descriptor) +} diff --git a/vendor/github.com/robfig/cron/spec.go b/vendor/github.com/robfig/cron/spec.go new file mode 100644 index 00000000000..aac9a60b954 --- /dev/null +++ b/vendor/github.com/robfig/cron/spec.go @@ -0,0 +1,158 @@ +package cron + +import "time" + +// SpecSchedule specifies a duty cycle (to the second granularity), based on a +// traditional crontab specification. It is computed initially and stored as bit sets. +type SpecSchedule struct { + Second, Minute, Hour, Dom, Month, Dow uint64 +} + +// bounds provides a range of acceptable values (plus a map of name to value). +type bounds struct { + min, max uint + names map[string]uint +} + +// The bounds for each field. +var ( + seconds = bounds{0, 59, nil} + minutes = bounds{0, 59, nil} + hours = bounds{0, 23, nil} + dom = bounds{1, 31, nil} + months = bounds{1, 12, map[string]uint{ + "jan": 1, + "feb": 2, + "mar": 3, + "apr": 4, + "may": 5, + "jun": 6, + "jul": 7, + "aug": 8, + "sep": 9, + "oct": 10, + "nov": 11, + "dec": 12, + }} + dow = bounds{0, 6, map[string]uint{ + "sun": 0, + "mon": 1, + "tue": 2, + "wed": 3, + "thu": 4, + "fri": 5, + "sat": 6, + }} +) + +const ( + // Set the top bit if a star was included in the expression. + starBit = 1 << 63 +) + +// Next returns the next time this schedule is activated, greater than the given +// time. If no time can be found to satisfy the schedule, return the zero time. +func (s *SpecSchedule) Next(t time.Time) time.Time { + // General approach: + // For Month, Day, Hour, Minute, Second: + // Check if the time value matches. If yes, continue to the next field. + // If the field doesn't match the schedule, then increment the field until it matches. + // While incrementing the field, a wrap-around brings it back to the beginning + // of the field list (since it is necessary to re-verify previous field + // values) + + // Start at the earliest possible time (the upcoming second). + t = t.Add(1*time.Second - time.Duration(t.Nanosecond())*time.Nanosecond) + + // This flag indicates whether a field has been incremented. + added := false + + // If no time is found within five years, return zero. + yearLimit := t.Year() + 5 + +WRAP: + if t.Year() > yearLimit { + return time.Time{} + } + + // Find the first applicable month. + // If it's this month, then do nothing. + for 1< 0 + dowMatch bool = 1< 0 + ) + if s.Dom&starBit > 0 || s.Dow&starBit > 0 { + return domMatch && dowMatch + } + return domMatch || dowMatch +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/controller/controllerutil/controllerutil.go b/vendor/sigs.k8s.io/controller-runtime/pkg/controller/controllerutil/controllerutil.go new file mode 100644 index 00000000000..d918eeaa42e --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/controller/controllerutil/controllerutil.go @@ -0,0 +1,178 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT 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 controllerutil + +import ( + "context" + "fmt" + "reflect" + + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/apiutil" +) + +// AlreadyOwnedError is an error returned if the object you are trying to assign +// a controller reference is already owned by another controller Object is the +// subject and Owner is the reference for the current owner +type AlreadyOwnedError struct { + Object v1.Object + Owner v1.OwnerReference +} + +func (e *AlreadyOwnedError) Error() string { + return fmt.Sprintf("Object %s/%s is already owned by another %s controller %s", e.Object.GetNamespace(), e.Object.GetName(), e.Owner.Kind, e.Owner.Name) +} + +func newAlreadyOwnedError(Object v1.Object, Owner v1.OwnerReference) *AlreadyOwnedError { + return &AlreadyOwnedError{ + Object: Object, + Owner: Owner, + } +} + +// SetControllerReference sets owner as a Controller OwnerReference on owned. +// This is used for garbage collection of the owned object and for +// reconciling the owner object on changes to owned (with a Watch + EnqueueRequestForOwner). +// Since only one OwnerReference can be a controller, it returns an error if +// there is another OwnerReference with Controller flag set. +func SetControllerReference(owner, object v1.Object, scheme *runtime.Scheme) error { + ro, ok := owner.(runtime.Object) + if !ok { + return fmt.Errorf("is not a %T a runtime.Object, cannot call SetControllerReference", owner) + } + + gvk, err := apiutil.GVKForObject(ro, scheme) + if err != nil { + return err + } + + // Create a new ref + ref := *v1.NewControllerRef(owner, schema.GroupVersionKind{Group: gvk.Group, Version: gvk.Version, Kind: gvk.Kind}) + + existingRefs := object.GetOwnerReferences() + fi := -1 + for i, r := range existingRefs { + if referSameObject(ref, r) { + fi = i + } else if r.Controller != nil && *r.Controller { + return newAlreadyOwnedError(object, r) + } + } + if fi == -1 { + existingRefs = append(existingRefs, ref) + } else { + existingRefs[fi] = ref + } + + // Update owner references + object.SetOwnerReferences(existingRefs) + return nil +} + +// Returns true if a and b point to the same object +func referSameObject(a, b v1.OwnerReference) bool { + aGV, err := schema.ParseGroupVersion(a.APIVersion) + if err != nil { + return false + } + + bGV, err := schema.ParseGroupVersion(b.APIVersion) + if err != nil { + return false + } + + return aGV == bGV && a.Kind == b.Kind && a.Name == b.Name +} + +// OperationResult is the action result of a CreateOrUpdate call +type OperationResult string + +const ( // They should complete the sentence "Deployment default/foo has been ..." + // OperationResultNone means that the resource has not been changed + OperationResultNone OperationResult = "unchanged" + // OperationResultCreated means that a new resource is created + OperationResultCreated OperationResult = "created" + // OperationResultUpdated means that an existing resource is updated + OperationResultUpdated OperationResult = "updated" +) + +// CreateOrUpdate creates or updates the given object obj in the Kubernetes +// cluster. The object's desired state should be reconciled with the existing +// state using the passed in ReconcileFn. obj must be a struct pointer so that +// obj can be updated with the content returned by the Server. +// +// It returns the executed operation and an error. +func CreateOrUpdate(ctx context.Context, c client.Client, obj runtime.Object, f MutateFn) (OperationResult, error) { + // op is the operation we are going to attempt + op := OperationResultNone + + // get the existing object meta + metaObj, ok := obj.(v1.Object) + if !ok { + return OperationResultNone, fmt.Errorf("%T does not implement metav1.Object interface", obj) + } + + // retrieve the existing object + key := client.ObjectKey{ + Name: metaObj.GetName(), + Namespace: metaObj.GetNamespace(), + } + err := c.Get(ctx, key, obj) + + // reconcile the existing object + existing := obj.DeepCopyObject() + existingObjMeta := existing.(v1.Object) + existingObjMeta.SetName(metaObj.GetName()) + existingObjMeta.SetNamespace(metaObj.GetNamespace()) + + if e := f(obj); e != nil { + return OperationResultNone, e + } + + if metaObj.GetName() != existingObjMeta.GetName() { + return OperationResultNone, fmt.Errorf("ReconcileFn cannot mutate objects name") + } + + if metaObj.GetNamespace() != existingObjMeta.GetNamespace() { + return OperationResultNone, fmt.Errorf("ReconcileFn cannot mutate objects namespace") + } + + if errors.IsNotFound(err) { + err = c.Create(ctx, obj) + op = OperationResultCreated + } else if err == nil { + if reflect.DeepEqual(existing, obj) { + return OperationResultNone, nil + } + err = c.Update(ctx, obj) + op = OperationResultUpdated + } else { + return OperationResultNone, err + } + + if err != nil { + op = OperationResultNone + } + return op, err +} + +// MutateFn is a function which mutates the existing object into it's desired state. +type MutateFn func(existing runtime.Object) error diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/controller/controllerutil/doc.go b/vendor/sigs.k8s.io/controller-runtime/pkg/controller/controllerutil/doc.go new file mode 100644 index 00000000000..ab386b29cdb --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/controller/controllerutil/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT 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 controllerutil contains utility functions for working with and implementing Controllers. +*/ +package controllerutil diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/runtime/scheme/scheme.go b/vendor/sigs.k8s.io/controller-runtime/pkg/runtime/scheme/scheme.go new file mode 100644 index 00000000000..79868214e34 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/runtime/scheme/scheme.go @@ -0,0 +1,56 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT 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 scheme + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +// Builder builds a new Scheme for mapping go types to Kubernetes GroupVersionKinds. +type Builder struct { + GroupVersion schema.GroupVersion + runtime.SchemeBuilder +} + +// Register adds one or objects to the SchemeBuilder so they can be added to a Scheme. Register mutates bld. +func (bld *Builder) Register(object ...runtime.Object) *Builder { + bld.SchemeBuilder.Register(func(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(bld.GroupVersion, object...) + metav1.AddToGroupVersion(scheme, bld.GroupVersion) + return nil + }) + return bld +} + +// RegisterAll registers all types from the Builder argument. RegisterAll mutates bld. +func (bld *Builder) RegisterAll(b *Builder) *Builder { + bld.SchemeBuilder = append(bld.SchemeBuilder, b.SchemeBuilder...) + return bld +} + +// AddToScheme adds all registered types to s. +func (bld *Builder) AddToScheme(s *runtime.Scheme) error { + return bld.SchemeBuilder.AddToScheme(s) +} + +// Build returns a new Scheme containing the registered types. +func (bld *Builder) Build() (*runtime.Scheme, error) { + s := runtime.NewScheme() + return s, bld.AddToScheme(s) +} From 0ee6bfd461fe0f7e6c9ab57d6712ababfabdbe87 Mon Sep 17 00:00:00 2001 From: Scott Nichols Date: Tue, 23 Apr 2019 09:06:34 -0700 Subject: [PATCH 03/25] Move ContainerSource API. --- config/300-cronjobsource.yaml | 84 ++++ hack/update-codegen.sh | 2 +- pkg/apis/sources/register.go | 21 + .../sources/v1alpha1/cron_job_lifecycle.go | 95 +++++ .../v1alpha1/cron_job_lifecycle_test.go | 376 ++++++++++++++++++ pkg/apis/sources/v1alpha1/cron_job_types.go | 83 ++++ pkg/apis/sources/v1alpha1/doc.go | 20 + pkg/apis/sources/v1alpha1/register.go | 53 +++ pkg/apis/sources/v1alpha1/register_test.go | 67 ++++ .../sources/v1alpha1/zz_generated.deepcopy.go | 125 ++++++ pkg/client/clientset/versioned/clientset.go | 22 + .../versioned/fake/clientset_generated.go | 12 + .../clientset/versioned/fake/register.go | 2 + .../clientset/versioned/scheme/register.go | 2 + .../typed/sources/v1alpha1/cronjobsource.go | 174 ++++++++ .../versioned/typed/sources/v1alpha1/doc.go | 20 + .../typed/sources/v1alpha1/fake/doc.go | 20 + .../v1alpha1/fake/fake_cronjobsource.go | 140 +++++++ .../v1alpha1/fake/fake_sources_client.go | 40 ++ .../sources/v1alpha1/generated_expansion.go | 21 + .../typed/sources/v1alpha1/sources_client.go | 90 +++++ .../informers/externalversions/factory.go | 6 + .../informers/externalversions/generic.go | 5 + .../externalversions/sources/interface.go | 46 +++ .../sources/v1alpha1/cronjobsource.go | 89 +++++ .../sources/v1alpha1/interface.go | 45 +++ .../listers/sources/v1alpha1/cronjobsource.go | 94 +++++ .../sources/v1alpha1/expansion_generated.go | 27 ++ 28 files changed, 1780 insertions(+), 1 deletion(-) create mode 100644 config/300-cronjobsource.yaml create mode 100644 pkg/apis/sources/register.go create mode 100644 pkg/apis/sources/v1alpha1/cron_job_lifecycle.go create mode 100644 pkg/apis/sources/v1alpha1/cron_job_lifecycle_test.go create mode 100644 pkg/apis/sources/v1alpha1/cron_job_types.go create mode 100644 pkg/apis/sources/v1alpha1/doc.go create mode 100644 pkg/apis/sources/v1alpha1/register.go create mode 100644 pkg/apis/sources/v1alpha1/register_test.go create mode 100644 pkg/apis/sources/v1alpha1/zz_generated.deepcopy.go create mode 100644 pkg/client/clientset/versioned/typed/sources/v1alpha1/cronjobsource.go create mode 100644 pkg/client/clientset/versioned/typed/sources/v1alpha1/doc.go create mode 100644 pkg/client/clientset/versioned/typed/sources/v1alpha1/fake/doc.go create mode 100644 pkg/client/clientset/versioned/typed/sources/v1alpha1/fake/fake_cronjobsource.go create mode 100644 pkg/client/clientset/versioned/typed/sources/v1alpha1/fake/fake_sources_client.go create mode 100644 pkg/client/clientset/versioned/typed/sources/v1alpha1/generated_expansion.go create mode 100644 pkg/client/clientset/versioned/typed/sources/v1alpha1/sources_client.go create mode 100644 pkg/client/informers/externalversions/sources/interface.go create mode 100644 pkg/client/informers/externalversions/sources/v1alpha1/cronjobsource.go create mode 100644 pkg/client/informers/externalversions/sources/v1alpha1/interface.go create mode 100644 pkg/client/listers/sources/v1alpha1/cronjobsource.go create mode 100644 pkg/client/listers/sources/v1alpha1/expansion_generated.go diff --git a/config/300-cronjobsource.yaml b/config/300-cronjobsource.yaml new file mode 100644 index 00000000000..50974d4718e --- /dev/null +++ b/config/300-cronjobsource.yaml @@ -0,0 +1,84 @@ +# 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: + labels: + eventing.knative.dev/source: "true" + knative.dev/crd-install: "true" + name: cronjobsources.sources.eventing.knative.dev +spec: + group: sources.eventing.knative.dev + names: + categories: + - all + - knative + - eventing + - sources + kind: CronJobSource + plural: cronjobsources + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + data: + type: string + schedule: + type: string + serviceAccountName: + type: string + sink: + type: object + required: + - schedule + type: object + status: + properties: + conditions: + items: + properties: + lastTransitionTime: + # we use a string in the stored object but a wrapper object + # at runtime. + type: string + message: + type: string + reason: + type: string + severity: + type: string + status: + type: string + type: + type: string + required: + - type + - status + type: object + type: array + sinkUri: + type: string + type: object + version: v1alpha1 diff --git a/hack/update-codegen.sh b/hack/update-codegen.sh index b651c1fc19a..dea5391fec7 100755 --- a/hack/update-codegen.sh +++ b/hack/update-codegen.sh @@ -28,7 +28,7 @@ CODEGEN_PKG=${CODEGEN_PKG:-$(cd ${REPO_ROOT_DIR}; ls -d -1 ./vendor/k8s.io/code- # instead of the $GOPATH directly. For normal projects this can be dropped. ${CODEGEN_PKG}/generate-groups.sh "deepcopy,client,informer,lister" \ github.com/knative/eventing/pkg/client github.com/knative/eventing/pkg/apis \ - "eventing:v1alpha1" \ + "eventing:v1alpha1 sources:v1alpha1" \ --go-header-file ${REPO_ROOT_DIR}/hack/boilerplate/boilerplate.go.txt # Only deepcopy the Duck types, as they are not real resources. diff --git a/pkg/apis/sources/register.go b/pkg/apis/sources/register.go new file mode 100644 index 00000000000..4d2a4477695 --- /dev/null +++ b/pkg/apis/sources/register.go @@ -0,0 +1,21 @@ +/* +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 sources + +const ( + GroupName = "sources.eventing.knative.dev" +) diff --git a/pkg/apis/sources/v1alpha1/cron_job_lifecycle.go b/pkg/apis/sources/v1alpha1/cron_job_lifecycle.go new file mode 100644 index 00000000000..3df28a080df --- /dev/null +++ b/pkg/apis/sources/v1alpha1/cron_job_lifecycle.go @@ -0,0 +1,95 @@ +/* +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" +) + +const ( + // CronJobConditionReady has status True when the CronJobSource is ready to send events. + CronJobConditionReady = duckv1alpha1.ConditionReady + + // CronJobConditionValidSchedule has status True when the CronJobSource has been configured with a valid schedule. + CronJobConditionValidSchedule duckv1alpha1.ConditionType = "ValidSchedule" + + // CronJobConditionSinkProvided has status True when the CronJobSource has been configured with a sink target. + CronJobConditionSinkProvided duckv1alpha1.ConditionType = "SinkProvided" + + // CronJobConditionDeployed has status True when the CronJobSource has had it's receive adapter deployment created. + CronJobConditionDeployed duckv1alpha1.ConditionType = "Deployed" +) + +var cronJobSourceCondSet = duckv1alpha1.NewLivingConditionSet( + CronJobConditionValidSchedule, + CronJobConditionSinkProvided, + CronJobConditionDeployed) + +// GetCondition returns the condition currently associated with the given type, or nil. +func (s *CronJobSourceStatus) GetCondition(t duckv1alpha1.ConditionType) *duckv1alpha1.Condition { + return cronJobSourceCondSet.Manage(s).GetCondition(t) +} + +// IsReady returns true if the resource is ready overall. +func (s *CronJobSourceStatus) IsReady() bool { + return cronJobSourceCondSet.Manage(s).IsHappy() +} + +// InitializeConditions sets relevant unset conditions to Unknown state. +func (s *CronJobSourceStatus) InitializeConditions() { + cronJobSourceCondSet.Manage(s).InitializeConditions() +} + +// MarkSchedule sets the condition that the source has a valid schedule configured. +func (s *CronJobSourceStatus) MarkSchedule() { + cronJobSourceCondSet.Manage(s).MarkTrue(CronJobConditionValidSchedule) +} + +// MarkInvalidSchedule sets the condition that the source does not have a valid schedule configured. +func (s *CronJobSourceStatus) MarkInvalidSchedule(reason, messageFormat string, messageA ...interface{}) { + cronJobSourceCondSet.Manage(s).MarkFalse(CronJobConditionValidSchedule, reason, messageFormat, messageA...) +} + +// MarkSink sets the condition that the source has a sink configured. +func (s *CronJobSourceStatus) MarkSink(uri string) { + s.SinkURI = uri + if len(uri) > 0 { + cronJobSourceCondSet.Manage(s).MarkTrue(CronJobConditionSinkProvided) + } else { + cronJobSourceCondSet.Manage(s).MarkUnknown(CronJobConditionSinkProvided, "SinkEmpty", "Sink has resolved to empty.%s", "") + } +} + +// MarkNoSink sets the condition that the source does not have a sink configured. +func (s *CronJobSourceStatus) MarkNoSink(reason, messageFormat string, messageA ...interface{}) { + cronJobSourceCondSet.Manage(s).MarkFalse(CronJobConditionSinkProvided, reason, messageFormat, messageA...) +} + +// MarkDeployed sets the condition that the source has been deployed. +func (s *CronJobSourceStatus) MarkDeployed() { + cronJobSourceCondSet.Manage(s).MarkTrue(CronJobConditionDeployed) +} + +// MarkDeploying sets the condition that the source is deploying. +func (s *CronJobSourceStatus) MarkDeploying(reason, messageFormat string, messageA ...interface{}) { + cronJobSourceCondSet.Manage(s).MarkUnknown(CronJobConditionDeployed, reason, messageFormat, messageA...) +} + +// MarkNotDeployed sets the condition that the source has not been deployed. +func (s *CronJobSourceStatus) MarkNotDeployed(reason, messageFormat string, messageA ...interface{}) { + cronJobSourceCondSet.Manage(s).MarkFalse(CronJobConditionDeployed, reason, messageFormat, messageA...) +} diff --git a/pkg/apis/sources/v1alpha1/cron_job_lifecycle_test.go b/pkg/apis/sources/v1alpha1/cron_job_lifecycle_test.go new file mode 100644 index 00000000000..9dd7aaefb88 --- /dev/null +++ b/pkg/apis/sources/v1alpha1/cron_job_lifecycle_test.go @@ -0,0 +1,376 @@ +/* +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_test + +import ( + "testing" + + corev1 "k8s.io/api/core/v1" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + "github.com/knative/eventing/pkg/apis/sources/v1alpha1" + duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" +) + +func TestCronJobSourceStatusIsReady(t *testing.T) { + tests := []struct { + name string + s *v1alpha1.CronJobSourceStatus + want bool + }{{ + name: "uninitialized", + s: &v1alpha1.CronJobSourceStatus{}, + want: false, + }, { + name: "initialized", + s: func() *v1alpha1.CronJobSourceStatus { + s := &v1alpha1.CronJobSourceStatus{} + s.InitializeConditions() + return s + }(), + want: false, + }, { + name: "mark deployed", + s: func() *v1alpha1.CronJobSourceStatus { + s := &v1alpha1.CronJobSourceStatus{} + s.InitializeConditions() + s.MarkDeployed() + return s + }(), + want: false, + }, { + name: "mark sink", + s: func() *v1alpha1.CronJobSourceStatus { + s := &v1alpha1.CronJobSourceStatus{} + s.InitializeConditions() + s.MarkSink("uri://example") + return s + }(), + want: false, + }, { + name: "mark schedule", + s: func() *v1alpha1.CronJobSourceStatus { + s := &v1alpha1.CronJobSourceStatus{} + s.InitializeConditions() + s.MarkSchedule() + return s + }(), + want: false, + }, { + name: "mark sink and deployed", + s: func() *v1alpha1.CronJobSourceStatus { + s := &v1alpha1.CronJobSourceStatus{} + s.InitializeConditions() + s.MarkSink("uri://example") + s.MarkDeployed() + return s + }(), + want: false, + }, { + name: "mark schedule and sink", + s: func() *v1alpha1.CronJobSourceStatus { + s := &v1alpha1.CronJobSourceStatus{} + s.InitializeConditions() + s.MarkSchedule() + s.MarkSink("uri://example") + return s + }(), + want: false, + }, { + name: "mark schedule, sink and deployed", + s: func() *v1alpha1.CronJobSourceStatus { + s := &v1alpha1.CronJobSourceStatus{} + s.InitializeConditions() + s.MarkSchedule() + s.MarkSink("uri://example") + s.MarkDeployed() + return s + }(), + want: true, + }, { + name: "mark schedule, sink and deployed then not deployed", + s: func() *v1alpha1.CronJobSourceStatus { + s := &v1alpha1.CronJobSourceStatus{} + s.InitializeConditions() + s.MarkSchedule() + s.MarkSink("uri://example") + s.MarkDeployed() + s.MarkNotDeployed("Testing", "") + return s + }(), + want: false, + }, { + name: "mark schedule, sink and not deployed then deploying then deployed", + s: func() *v1alpha1.CronJobSourceStatus { + s := &v1alpha1.CronJobSourceStatus{} + s.InitializeConditions() + s.MarkSchedule() + s.MarkSink("uri://example") + s.MarkNotDeployed("MarkNotDeployed", "") + s.MarkDeploying("MarkDeploying", "") + s.MarkDeployed() + return s + }(), + want: true, + }, { + name: "mark schedule validated, sink empty and deployed", + s: func() *v1alpha1.CronJobSourceStatus { + s := &v1alpha1.CronJobSourceStatus{} + s.InitializeConditions() + s.MarkSchedule() + s.MarkSink("") + s.MarkDeployed() + return s + }(), + want: false, + }, { + name: "mark schedule validated, sink empty and deployed then sink", + s: func() *v1alpha1.CronJobSourceStatus { + s := &v1alpha1.CronJobSourceStatus{} + s.InitializeConditions() + s.MarkSchedule() + s.MarkSink("") + s.MarkDeployed() + s.MarkSink("uri://example") + return s + }(), + want: true, + }} + + 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 TestCronJobSourceStatusGetCondition(t *testing.T) { + tests := []struct { + name string + s *v1alpha1.CronJobSourceStatus + condQuery duckv1alpha1.ConditionType + want *duckv1alpha1.Condition + }{{ + name: "uninitialized", + s: &v1alpha1.CronJobSourceStatus{}, + condQuery: v1alpha1.CronJobConditionReady, + want: nil, + }, { + name: "initialized", + s: func() *v1alpha1.CronJobSourceStatus { + s := &v1alpha1.CronJobSourceStatus{} + s.InitializeConditions() + return s + }(), + condQuery: v1alpha1.CronJobConditionReady, + want: &duckv1alpha1.Condition{ + Type: v1alpha1.CronJobConditionReady, + Status: corev1.ConditionUnknown, + }, + }, { + name: "mark deployed", + s: func() *v1alpha1.CronJobSourceStatus { + s := &v1alpha1.CronJobSourceStatus{} + s.InitializeConditions() + s.MarkDeployed() + return s + }(), + condQuery: v1alpha1.CronJobConditionReady, + want: &duckv1alpha1.Condition{ + Type: v1alpha1.CronJobConditionReady, + Status: corev1.ConditionUnknown, + }, + }, { + name: "mark sink", + s: func() *v1alpha1.CronJobSourceStatus { + s := &v1alpha1.CronJobSourceStatus{} + s.InitializeConditions() + s.MarkSink("uri://example") + return s + }(), + condQuery: v1alpha1.CronJobConditionReady, + want: &duckv1alpha1.Condition{ + Type: v1alpha1.CronJobConditionReady, + Status: corev1.ConditionUnknown, + }, + }, { + name: "mark schedule", + s: func() *v1alpha1.CronJobSourceStatus { + s := &v1alpha1.CronJobSourceStatus{} + s.InitializeConditions() + s.MarkSchedule() + return s + }(), + condQuery: v1alpha1.CronJobConditionReady, + want: &duckv1alpha1.Condition{ + Type: v1alpha1.CronJobConditionReady, + Status: corev1.ConditionUnknown, + }, + }, { + name: "mark schedule, sink and deployed", + s: func() *v1alpha1.CronJobSourceStatus { + s := &v1alpha1.CronJobSourceStatus{} + s.InitializeConditions() + s.MarkSchedule() + s.MarkSink("uri://example") + s.MarkDeployed() + return s + }(), + condQuery: v1alpha1.CronJobConditionReady, + want: &duckv1alpha1.Condition{ + Type: v1alpha1.CronJobConditionReady, + Status: corev1.ConditionTrue, + }, + }, { + name: "mark schedule, sink and deployed then no sink", + s: func() *v1alpha1.CronJobSourceStatus { + s := &v1alpha1.CronJobSourceStatus{} + s.InitializeConditions() + s.MarkSchedule() + s.MarkSink("uri://example") + s.MarkDeployed() + s.MarkNoSink("Testing", "hi%s", "") + return s + }(), + condQuery: v1alpha1.CronJobConditionReady, + want: &duckv1alpha1.Condition{ + Type: v1alpha1.CronJobConditionReady, + Status: corev1.ConditionFalse, + Reason: "Testing", + Message: "hi", + }, + }, { + name: "mark schedule, sink and deployed then invalid schedule", + s: func() *v1alpha1.CronJobSourceStatus { + s := &v1alpha1.CronJobSourceStatus{} + s.InitializeConditions() + s.MarkSchedule() + s.MarkSink("uri://example") + s.MarkDeployed() + s.MarkInvalidSchedule("Testing", "hi%s", "") + return s + }(), + condQuery: v1alpha1.CronJobConditionReady, + want: &duckv1alpha1.Condition{ + Type: v1alpha1.CronJobConditionReady, + Status: corev1.ConditionFalse, + Reason: "Testing", + Message: "hi", + }, + }, { + name: "mark schedule, sink and deployed then deploying", + s: func() *v1alpha1.CronJobSourceStatus { + s := &v1alpha1.CronJobSourceStatus{} + s.InitializeConditions() + s.MarkSchedule() + s.MarkSink("uri://example") + s.MarkDeployed() + s.MarkDeploying("Testing", "hi%s", "") + return s + }(), + condQuery: v1alpha1.CronJobConditionReady, + want: &duckv1alpha1.Condition{ + Type: v1alpha1.CronJobConditionReady, + Status: corev1.ConditionUnknown, + Reason: "Testing", + Message: "hi", + }, + }, { + name: "mark schedule, sink and deployed then not deployed", + s: func() *v1alpha1.CronJobSourceStatus { + s := &v1alpha1.CronJobSourceStatus{} + s.InitializeConditions() + s.MarkSchedule() + s.MarkSink("uri://example") + s.MarkDeployed() + s.MarkNotDeployed("Testing", "hi%s", "") + return s + }(), + condQuery: v1alpha1.CronJobConditionReady, + want: &duckv1alpha1.Condition{ + Type: v1alpha1.CronJobConditionReady, + Status: corev1.ConditionFalse, + Reason: "Testing", + Message: "hi", + }, + }, { + name: "mark schedule, sink and not deployed then deploying then deployed", + s: func() *v1alpha1.CronJobSourceStatus { + s := &v1alpha1.CronJobSourceStatus{} + s.InitializeConditions() + s.MarkSchedule() + s.MarkSink("uri://example") + s.MarkNotDeployed("MarkNotDeployed", "%s", "") + s.MarkDeploying("MarkDeploying", "%s", "") + s.MarkDeployed() + return s + }(), + condQuery: v1alpha1.CronJobConditionReady, + want: &duckv1alpha1.Condition{ + Type: v1alpha1.CronJobConditionReady, + Status: corev1.ConditionTrue, + }, + }, { + name: "mark schedule, sink empty and deployed", + s: func() *v1alpha1.CronJobSourceStatus { + s := &v1alpha1.CronJobSourceStatus{} + s.InitializeConditions() + s.MarkSchedule() + s.MarkSink("") + s.MarkDeployed() + return s + }(), + condQuery: v1alpha1.CronJobConditionReady, + want: &duckv1alpha1.Condition{ + Type: v1alpha1.CronJobConditionReady, + Status: corev1.ConditionUnknown, + Reason: "SinkEmpty", + Message: "Sink has resolved to empty.", + }, + }, { + name: "mark schedule, sink empty and deployed then sink", + s: func() *v1alpha1.CronJobSourceStatus { + s := &v1alpha1.CronJobSourceStatus{} + s.InitializeConditions() + s.MarkSchedule() + s.MarkSink("") + s.MarkDeployed() + s.MarkSink("uri://example") + return s + }(), + condQuery: v1alpha1.CronJobConditionReady, + want: &duckv1alpha1.Condition{ + Type: v1alpha1.CronJobConditionReady, + Status: corev1.ConditionTrue, + }, + }} + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := test.s.GetCondition(test.condQuery) + ignoreTime := cmpopts.IgnoreFields(duckv1alpha1.Condition{}, + "LastTransitionTime", "Severity") + if diff := cmp.Diff(test.want, got, ignoreTime); diff != "" { + t.Errorf("unexpected condition (-want, +got) = %v", diff) + } + }) + } +} diff --git a/pkg/apis/sources/v1alpha1/cron_job_types.go b/pkg/apis/sources/v1alpha1/cron_job_types.go new file mode 100644 index 00000000000..df6f69d9197 --- /dev/null +++ b/pkg/apis/sources/v1alpha1/cron_job_types.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 ( + "github.com/knative/pkg/apis/duck" + duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// CronJobSource is the Schema for the cronjobsources API. +type CronJobSource struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec CronJobSourceSpec `json:"spec,omitempty"` + Status CronJobSourceStatus `json:"status,omitempty"` +} + +// Check that CronJobSource can be validated and can be defaulted. +var _ runtime.Object = (*CronJobSource)(nil) + +// Check that CronJobSource implements the Conditions duck type. +var _ = duck.VerifyType(&CronJobSource{}, &duckv1alpha1.Conditions{}) + +// CronJobSourceSpec defines the desired state of the CronJobSource. +type CronJobSourceSpec struct { + + // Schedule is the cronjob schedule. + // +required + Schedule string `json:"schedule"` + + // Data is the data posted to the target function. + Data string `json:"data,omitempty"` + + // Sink is a reference to an object that will resolve to a domain name to use as the sink. + // +optional + Sink *corev1.ObjectReference `json:"sink,omitempty"` + + // ServiceAccoutName is the name of the ServiceAccount that will be used to run the Receive + // Adapter Deployment. + ServiceAccountName string `json:"serviceAccountName,omitempty"` +} + +// CronJobSourceStatus defines the observed state of CronJobSource. +type CronJobSourceStatus struct { + // 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"` + + // SinkURI is the current active sink URI that has been configured for the CronJobSource. + // +optional + SinkURI string `json:"sinkUri,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// CronJobSourceList contains a list of CronJobSources. +type CronJobSourceList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []CronJobSource `json:"items"` +} diff --git a/pkg/apis/sources/v1alpha1/doc.go b/pkg/apis/sources/v1alpha1/doc.go new file mode 100644 index 00000000000..7d7f6738fbc --- /dev/null +++ b/pkg/apis/sources/v1alpha1/doc.go @@ -0,0 +1,20 @@ +/* +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 contains API Schema definitions for the sources v1alpha1 API group +// +k8s:deepcopy-gen=package +// +groupName=sources.eventing.knative.dev +package v1alpha1 diff --git a/pkg/apis/sources/v1alpha1/register.go b/pkg/apis/sources/v1alpha1/register.go new file mode 100644 index 00000000000..fa8640fc93f --- /dev/null +++ b/pkg/apis/sources/v1alpha1/register.go @@ -0,0 +1,53 @@ +/* +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/eventing/pkg/apis/sources" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +// SchemeGroupVersion is group version used to register these objects +var SchemeGroupVersion = schema.GroupVersion{Group: sources.GroupName, Version: "v1alpha1"} + +// Kind takes an unqualified kind and returns back a Group qualified GroupKind +func Kind(kind string) schema.GroupKind { + return SchemeGroupVersion.WithKind(kind).GroupKind() +} + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +var ( + SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) + AddToScheme = SchemeBuilder.AddToScheme +) + +// Adds the list of known types to Scheme. +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + &CronJobSource{}, + &CronJobSourceList{}, + ) + metav1.AddToGroupVersion(scheme, SchemeGroupVersion) + return nil +} diff --git a/pkg/apis/sources/v1alpha1/register_test.go b/pkg/apis/sources/v1alpha1/register_test.go new file mode 100644 index 00000000000..737b89bc292 --- /dev/null +++ b/pkg/apis/sources/v1alpha1/register_test.go @@ -0,0 +1,67 @@ +/* +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" + + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + + "github.com/google/go-cmp/cmp" +) + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func TestResource(t *testing.T) { + want := schema.GroupResource{ + Group: "sources.eventing.knative.dev", + Resource: "foo", + } + + got := Resource("foo") + + if diff := cmp.Diff(want, got); diff != "" { + t.Errorf("unexpected resource (-want, +got) = %v", diff) + } +} + +// Kind takes an unqualified resource and returns a Group qualified GroupKind +func TestKind(t *testing.T) { + want := schema.GroupKind{ + Group: "sources.eventing.knative.dev", + Kind: "kind", + } + + got := Kind("kind") + + if diff := cmp.Diff(want, got); diff != "" { + t.Errorf("unexpected resource (-want, +got) = %v", diff) + } +} + +// TestKnownTypes makes sure that expected types get added. +func TestKnownTypes(t *testing.T) { + scheme := runtime.NewScheme() + addKnownTypes(scheme) + types := scheme.KnownTypes(SchemeGroupVersion) + + for _, name := range []string{ + "CronJobSource", + "CronJobSourceList", + } { + if _, ok := types[name]; !ok { + t.Errorf("Did not find %q as registered type", name) + } + } + +} diff --git a/pkg/apis/sources/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/sources/v1alpha1/zz_generated.deepcopy.go new file mode 100644 index 00000000000..27618a2b621 --- /dev/null +++ b/pkg/apis/sources/v1alpha1/zz_generated.deepcopy.go @@ -0,0 +1,125 @@ +// +build !ignore_autogenerated + +/* +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 deepcopy-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + v1 "k8s.io/api/core/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 *CronJobSource) DeepCopyInto(out *CronJobSource) { + *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 CronJobSource. +func (in *CronJobSource) DeepCopy() *CronJobSource { + if in == nil { + return nil + } + out := new(CronJobSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *CronJobSource) 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 *CronJobSourceList) DeepCopyInto(out *CronJobSourceList) { + *out = *in + out.TypeMeta = in.TypeMeta + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]CronJobSource, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CronJobSourceList. +func (in *CronJobSourceList) DeepCopy() *CronJobSourceList { + if in == nil { + return nil + } + out := new(CronJobSourceList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *CronJobSourceList) 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 *CronJobSourceSpec) DeepCopyInto(out *CronJobSourceSpec) { + *out = *in + if in.Sink != nil { + in, out := &in.Sink, &out.Sink + *out = new(v1.ObjectReference) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CronJobSourceSpec. +func (in *CronJobSourceSpec) DeepCopy() *CronJobSourceSpec { + if in == nil { + return nil + } + out := new(CronJobSourceSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CronJobSourceStatus) DeepCopyInto(out *CronJobSourceStatus) { + *out = *in + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CronJobSourceStatus. +func (in *CronJobSourceStatus) DeepCopy() *CronJobSourceStatus { + if in == nil { + return nil + } + out := new(CronJobSourceStatus) + in.DeepCopyInto(out) + return out +} diff --git a/pkg/client/clientset/versioned/clientset.go b/pkg/client/clientset/versioned/clientset.go index 4f8f6c7c4c3..1c27aed4eb5 100644 --- a/pkg/client/clientset/versioned/clientset.go +++ b/pkg/client/clientset/versioned/clientset.go @@ -20,6 +20,7 @@ package versioned import ( eventingv1alpha1 "github.com/knative/eventing/pkg/client/clientset/versioned/typed/eventing/v1alpha1" + sourcesv1alpha1 "github.com/knative/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha1" discovery "k8s.io/client-go/discovery" rest "k8s.io/client-go/rest" flowcontrol "k8s.io/client-go/util/flowcontrol" @@ -30,6 +31,9 @@ type Interface interface { EventingV1alpha1() eventingv1alpha1.EventingV1alpha1Interface // Deprecated: please explicitly pick a version if possible. Eventing() eventingv1alpha1.EventingV1alpha1Interface + SourcesV1alpha1() sourcesv1alpha1.SourcesV1alpha1Interface + // Deprecated: please explicitly pick a version if possible. + Sources() sourcesv1alpha1.SourcesV1alpha1Interface } // Clientset contains the clients for groups. Each group has exactly one @@ -37,6 +41,7 @@ type Interface interface { type Clientset struct { *discovery.DiscoveryClient eventingV1alpha1 *eventingv1alpha1.EventingV1alpha1Client + sourcesV1alpha1 *sourcesv1alpha1.SourcesV1alpha1Client } // EventingV1alpha1 retrieves the EventingV1alpha1Client @@ -50,6 +55,17 @@ func (c *Clientset) Eventing() eventingv1alpha1.EventingV1alpha1Interface { return c.eventingV1alpha1 } +// SourcesV1alpha1 retrieves the SourcesV1alpha1Client +func (c *Clientset) SourcesV1alpha1() sourcesv1alpha1.SourcesV1alpha1Interface { + return c.sourcesV1alpha1 +} + +// Deprecated: Sources retrieves the default version of SourcesClient. +// Please explicitly pick a version. +func (c *Clientset) Sources() sourcesv1alpha1.SourcesV1alpha1Interface { + return c.sourcesV1alpha1 +} + // Discovery retrieves the DiscoveryClient func (c *Clientset) Discovery() discovery.DiscoveryInterface { if c == nil { @@ -70,6 +86,10 @@ func NewForConfig(c *rest.Config) (*Clientset, error) { if err != nil { return nil, err } + cs.sourcesV1alpha1, err = sourcesv1alpha1.NewForConfig(&configShallowCopy) + if err != nil { + return nil, err + } cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfig(&configShallowCopy) if err != nil { @@ -83,6 +103,7 @@ func NewForConfig(c *rest.Config) (*Clientset, error) { func NewForConfigOrDie(c *rest.Config) *Clientset { var cs Clientset cs.eventingV1alpha1 = eventingv1alpha1.NewForConfigOrDie(c) + cs.sourcesV1alpha1 = sourcesv1alpha1.NewForConfigOrDie(c) cs.DiscoveryClient = discovery.NewDiscoveryClientForConfigOrDie(c) return &cs @@ -92,6 +113,7 @@ func NewForConfigOrDie(c *rest.Config) *Clientset { func New(c rest.Interface) *Clientset { var cs Clientset cs.eventingV1alpha1 = eventingv1alpha1.New(c) + cs.sourcesV1alpha1 = sourcesv1alpha1.New(c) cs.DiscoveryClient = discovery.NewDiscoveryClient(c) return &cs diff --git a/pkg/client/clientset/versioned/fake/clientset_generated.go b/pkg/client/clientset/versioned/fake/clientset_generated.go index 0a4b10bfa14..c539ac22f55 100644 --- a/pkg/client/clientset/versioned/fake/clientset_generated.go +++ b/pkg/client/clientset/versioned/fake/clientset_generated.go @@ -22,6 +22,8 @@ import ( clientset "github.com/knative/eventing/pkg/client/clientset/versioned" eventingv1alpha1 "github.com/knative/eventing/pkg/client/clientset/versioned/typed/eventing/v1alpha1" fakeeventingv1alpha1 "github.com/knative/eventing/pkg/client/clientset/versioned/typed/eventing/v1alpha1/fake" + sourcesv1alpha1 "github.com/knative/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha1" + fakesourcesv1alpha1 "github.com/knative/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha1/fake" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/watch" "k8s.io/client-go/discovery" @@ -80,3 +82,13 @@ func (c *Clientset) EventingV1alpha1() eventingv1alpha1.EventingV1alpha1Interfac func (c *Clientset) Eventing() eventingv1alpha1.EventingV1alpha1Interface { return &fakeeventingv1alpha1.FakeEventingV1alpha1{Fake: &c.Fake} } + +// SourcesV1alpha1 retrieves the SourcesV1alpha1Client +func (c *Clientset) SourcesV1alpha1() sourcesv1alpha1.SourcesV1alpha1Interface { + return &fakesourcesv1alpha1.FakeSourcesV1alpha1{Fake: &c.Fake} +} + +// Sources retrieves the SourcesV1alpha1Client +func (c *Clientset) Sources() sourcesv1alpha1.SourcesV1alpha1Interface { + return &fakesourcesv1alpha1.FakeSourcesV1alpha1{Fake: &c.Fake} +} diff --git a/pkg/client/clientset/versioned/fake/register.go b/pkg/client/clientset/versioned/fake/register.go index 60103d7155b..5d1afb6a6e2 100644 --- a/pkg/client/clientset/versioned/fake/register.go +++ b/pkg/client/clientset/versioned/fake/register.go @@ -20,6 +20,7 @@ package fake import ( eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" + sourcesv1alpha1 "github.com/knative/eventing/pkg/apis/sources/v1alpha1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" schema "k8s.io/apimachinery/pkg/runtime/schema" @@ -32,6 +33,7 @@ var codecs = serializer.NewCodecFactory(scheme) var parameterCodec = runtime.NewParameterCodec(scheme) var localSchemeBuilder = runtime.SchemeBuilder{ eventingv1alpha1.AddToScheme, + sourcesv1alpha1.AddToScheme, } // AddToScheme adds all types of this clientset into the given scheme. This allows composition diff --git a/pkg/client/clientset/versioned/scheme/register.go b/pkg/client/clientset/versioned/scheme/register.go index a6263f98cb9..639371bf1db 100644 --- a/pkg/client/clientset/versioned/scheme/register.go +++ b/pkg/client/clientset/versioned/scheme/register.go @@ -20,6 +20,7 @@ package scheme import ( eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" + sourcesv1alpha1 "github.com/knative/eventing/pkg/apis/sources/v1alpha1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" schema "k8s.io/apimachinery/pkg/runtime/schema" @@ -32,6 +33,7 @@ var Codecs = serializer.NewCodecFactory(Scheme) var ParameterCodec = runtime.NewParameterCodec(Scheme) var localSchemeBuilder = runtime.SchemeBuilder{ eventingv1alpha1.AddToScheme, + sourcesv1alpha1.AddToScheme, } // AddToScheme adds all types of this clientset into the given scheme. This allows composition diff --git a/pkg/client/clientset/versioned/typed/sources/v1alpha1/cronjobsource.go b/pkg/client/clientset/versioned/typed/sources/v1alpha1/cronjobsource.go new file mode 100644 index 00000000000..f18f9c8150b --- /dev/null +++ b/pkg/client/clientset/versioned/typed/sources/v1alpha1/cronjobsource.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/sources/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" +) + +// CronJobSourcesGetter has a method to return a CronJobSourceInterface. +// A group's client should implement this interface. +type CronJobSourcesGetter interface { + CronJobSources(namespace string) CronJobSourceInterface +} + +// CronJobSourceInterface has methods to work with CronJobSource resources. +type CronJobSourceInterface interface { + Create(*v1alpha1.CronJobSource) (*v1alpha1.CronJobSource, error) + Update(*v1alpha1.CronJobSource) (*v1alpha1.CronJobSource, error) + UpdateStatus(*v1alpha1.CronJobSource) (*v1alpha1.CronJobSource, error) + Delete(name string, options *v1.DeleteOptions) error + DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error + Get(name string, options v1.GetOptions) (*v1alpha1.CronJobSource, error) + List(opts v1.ListOptions) (*v1alpha1.CronJobSourceList, error) + Watch(opts v1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.CronJobSource, err error) + CronJobSourceExpansion +} + +// cronJobSources implements CronJobSourceInterface +type cronJobSources struct { + client rest.Interface + ns string +} + +// newCronJobSources returns a CronJobSources +func newCronJobSources(c *SourcesV1alpha1Client, namespace string) *cronJobSources { + return &cronJobSources{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the cronJobSource, and returns the corresponding cronJobSource object, and an error if there is any. +func (c *cronJobSources) Get(name string, options v1.GetOptions) (result *v1alpha1.CronJobSource, err error) { + result = &v1alpha1.CronJobSource{} + err = c.client.Get(). + Namespace(c.ns). + Resource("cronjobsources"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of CronJobSources that match those selectors. +func (c *cronJobSources) List(opts v1.ListOptions) (result *v1alpha1.CronJobSourceList, err error) { + result = &v1alpha1.CronJobSourceList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("cronjobsources"). + VersionedParams(&opts, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested cronJobSources. +func (c *cronJobSources) Watch(opts v1.ListOptions) (watch.Interface, error) { + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("cronjobsources"). + VersionedParams(&opts, scheme.ParameterCodec). + Watch() +} + +// Create takes the representation of a cronJobSource and creates it. Returns the server's representation of the cronJobSource, and an error, if there is any. +func (c *cronJobSources) Create(cronJobSource *v1alpha1.CronJobSource) (result *v1alpha1.CronJobSource, err error) { + result = &v1alpha1.CronJobSource{} + err = c.client.Post(). + Namespace(c.ns). + Resource("cronjobsources"). + Body(cronJobSource). + Do(). + Into(result) + return +} + +// Update takes the representation of a cronJobSource and updates it. Returns the server's representation of the cronJobSource, and an error, if there is any. +func (c *cronJobSources) Update(cronJobSource *v1alpha1.CronJobSource) (result *v1alpha1.CronJobSource, err error) { + result = &v1alpha1.CronJobSource{} + err = c.client.Put(). + Namespace(c.ns). + Resource("cronjobsources"). + Name(cronJobSource.Name). + Body(cronJobSource). + 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 *cronJobSources) UpdateStatus(cronJobSource *v1alpha1.CronJobSource) (result *v1alpha1.CronJobSource, err error) { + result = &v1alpha1.CronJobSource{} + err = c.client.Put(). + Namespace(c.ns). + Resource("cronjobsources"). + Name(cronJobSource.Name). + SubResource("status"). + Body(cronJobSource). + Do(). + Into(result) + return +} + +// Delete takes name of the cronJobSource and deletes it. Returns an error if one occurs. +func (c *cronJobSources) Delete(name string, options *v1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("cronjobsources"). + Name(name). + Body(options). + Do(). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *cronJobSources) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("cronjobsources"). + VersionedParams(&listOptions, scheme.ParameterCodec). + Body(options). + Do(). + Error() +} + +// Patch applies the patch and returns the patched cronJobSource. +func (c *cronJobSources) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.CronJobSource, err error) { + result = &v1alpha1.CronJobSource{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("cronjobsources"). + SubResource(subresources...). + Name(name). + Body(data). + Do(). + Into(result) + return +} diff --git a/pkg/client/clientset/versioned/typed/sources/v1alpha1/doc.go b/pkg/client/clientset/versioned/typed/sources/v1alpha1/doc.go new file mode 100644 index 00000000000..75445c17900 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/sources/v1alpha1/doc.go @@ -0,0 +1,20 @@ +/* +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. + +// This package has the automatically generated typed clients. +package v1alpha1 diff --git a/pkg/client/clientset/versioned/typed/sources/v1alpha1/fake/doc.go b/pkg/client/clientset/versioned/typed/sources/v1alpha1/fake/doc.go new file mode 100644 index 00000000000..128aa183a91 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/sources/v1alpha1/fake/doc.go @@ -0,0 +1,20 @@ +/* +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 has the automatically generated clients. +package fake diff --git a/pkg/client/clientset/versioned/typed/sources/v1alpha1/fake/fake_cronjobsource.go b/pkg/client/clientset/versioned/typed/sources/v1alpha1/fake/fake_cronjobsource.go new file mode 100644 index 00000000000..f90c9761f1c --- /dev/null +++ b/pkg/client/clientset/versioned/typed/sources/v1alpha1/fake/fake_cronjobsource.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/sources/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" +) + +// FakeCronJobSources implements CronJobSourceInterface +type FakeCronJobSources struct { + Fake *FakeSourcesV1alpha1 + ns string +} + +var cronjobsourcesResource = schema.GroupVersionResource{Group: "sources.eventing.knative.dev", Version: "v1alpha1", Resource: "cronjobsources"} + +var cronjobsourcesKind = schema.GroupVersionKind{Group: "sources.eventing.knative.dev", Version: "v1alpha1", Kind: "CronJobSource"} + +// Get takes name of the cronJobSource, and returns the corresponding cronJobSource object, and an error if there is any. +func (c *FakeCronJobSources) Get(name string, options v1.GetOptions) (result *v1alpha1.CronJobSource, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(cronjobsourcesResource, c.ns, name), &v1alpha1.CronJobSource{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.CronJobSource), err +} + +// List takes label and field selectors, and returns the list of CronJobSources that match those selectors. +func (c *FakeCronJobSources) List(opts v1.ListOptions) (result *v1alpha1.CronJobSourceList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(cronjobsourcesResource, cronjobsourcesKind, c.ns, opts), &v1alpha1.CronJobSourceList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.CronJobSourceList{ListMeta: obj.(*v1alpha1.CronJobSourceList).ListMeta} + for _, item := range obj.(*v1alpha1.CronJobSourceList).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 cronJobSources. +func (c *FakeCronJobSources) Watch(opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(cronjobsourcesResource, c.ns, opts)) + +} + +// Create takes the representation of a cronJobSource and creates it. Returns the server's representation of the cronJobSource, and an error, if there is any. +func (c *FakeCronJobSources) Create(cronJobSource *v1alpha1.CronJobSource) (result *v1alpha1.CronJobSource, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(cronjobsourcesResource, c.ns, cronJobSource), &v1alpha1.CronJobSource{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.CronJobSource), err +} + +// Update takes the representation of a cronJobSource and updates it. Returns the server's representation of the cronJobSource, and an error, if there is any. +func (c *FakeCronJobSources) Update(cronJobSource *v1alpha1.CronJobSource) (result *v1alpha1.CronJobSource, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(cronjobsourcesResource, c.ns, cronJobSource), &v1alpha1.CronJobSource{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.CronJobSource), 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 *FakeCronJobSources) UpdateStatus(cronJobSource *v1alpha1.CronJobSource) (*v1alpha1.CronJobSource, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(cronjobsourcesResource, "status", c.ns, cronJobSource), &v1alpha1.CronJobSource{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.CronJobSource), err +} + +// Delete takes name of the cronJobSource and deletes it. Returns an error if one occurs. +func (c *FakeCronJobSources) Delete(name string, options *v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteAction(cronjobsourcesResource, c.ns, name), &v1alpha1.CronJobSource{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeCronJobSources) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(cronjobsourcesResource, c.ns, listOptions) + + _, err := c.Fake.Invokes(action, &v1alpha1.CronJobSourceList{}) + return err +} + +// Patch applies the patch and returns the patched cronJobSource. +func (c *FakeCronJobSources) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.CronJobSource, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(cronjobsourcesResource, c.ns, name, data, subresources...), &v1alpha1.CronJobSource{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.CronJobSource), err +} diff --git a/pkg/client/clientset/versioned/typed/sources/v1alpha1/fake/fake_sources_client.go b/pkg/client/clientset/versioned/typed/sources/v1alpha1/fake/fake_sources_client.go new file mode 100644 index 00000000000..14861734bd7 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/sources/v1alpha1/fake/fake_sources_client.go @@ -0,0 +1,40 @@ +/* +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/client/clientset/versioned/typed/sources/v1alpha1" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeSourcesV1alpha1 struct { + *testing.Fake +} + +func (c *FakeSourcesV1alpha1) CronJobSources(namespace string) v1alpha1.CronJobSourceInterface { + return &FakeCronJobSources{c, namespace} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeSourcesV1alpha1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/pkg/client/clientset/versioned/typed/sources/v1alpha1/generated_expansion.go b/pkg/client/clientset/versioned/typed/sources/v1alpha1/generated_expansion.go new file mode 100644 index 00000000000..e11588db657 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/sources/v1alpha1/generated_expansion.go @@ -0,0 +1,21 @@ +/* +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 + +type CronJobSourceExpansion interface{} diff --git a/pkg/client/clientset/versioned/typed/sources/v1alpha1/sources_client.go b/pkg/client/clientset/versioned/typed/sources/v1alpha1/sources_client.go new file mode 100644 index 00000000000..ef301678c43 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/sources/v1alpha1/sources_client.go @@ -0,0 +1,90 @@ +/* +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/sources/v1alpha1" + "github.com/knative/eventing/pkg/client/clientset/versioned/scheme" + serializer "k8s.io/apimachinery/pkg/runtime/serializer" + rest "k8s.io/client-go/rest" +) + +type SourcesV1alpha1Interface interface { + RESTClient() rest.Interface + CronJobSourcesGetter +} + +// SourcesV1alpha1Client is used to interact with features provided by the sources.eventing.knative.dev group. +type SourcesV1alpha1Client struct { + restClient rest.Interface +} + +func (c *SourcesV1alpha1Client) CronJobSources(namespace string) CronJobSourceInterface { + return newCronJobSources(c, namespace) +} + +// NewForConfig creates a new SourcesV1alpha1Client for the given config. +func NewForConfig(c *rest.Config) (*SourcesV1alpha1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + client, err := rest.RESTClientFor(&config) + if err != nil { + return nil, err + } + return &SourcesV1alpha1Client{client}, nil +} + +// NewForConfigOrDie creates a new SourcesV1alpha1Client for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *SourcesV1alpha1Client { + client, err := NewForConfig(c) + if err != nil { + panic(err) + } + return client +} + +// New creates a new SourcesV1alpha1Client for the given RESTClient. +func New(c rest.Interface) *SourcesV1alpha1Client { + return &SourcesV1alpha1Client{c} +} + +func setConfigDefaults(config *rest.Config) error { + gv := v1alpha1.SchemeGroupVersion + config.GroupVersion = &gv + config.APIPath = "/apis" + config.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: scheme.Codecs} + + if config.UserAgent == "" { + config.UserAgent = rest.DefaultKubernetesUserAgent() + } + + return nil +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *SourcesV1alpha1Client) RESTClient() rest.Interface { + if c == nil { + return nil + } + return c.restClient +} diff --git a/pkg/client/informers/externalversions/factory.go b/pkg/client/informers/externalversions/factory.go index 0cde7d2cdd1..51a86f08730 100644 --- a/pkg/client/informers/externalversions/factory.go +++ b/pkg/client/informers/externalversions/factory.go @@ -26,6 +26,7 @@ import ( versioned "github.com/knative/eventing/pkg/client/clientset/versioned" eventing "github.com/knative/eventing/pkg/client/informers/externalversions/eventing" internalinterfaces "github.com/knative/eventing/pkg/client/informers/externalversions/internalinterfaces" + sources "github.com/knative/eventing/pkg/client/informers/externalversions/sources" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" schema "k8s.io/apimachinery/pkg/runtime/schema" @@ -173,8 +174,13 @@ type SharedInformerFactory interface { WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool Eventing() eventing.Interface + Sources() sources.Interface } func (f *sharedInformerFactory) Eventing() eventing.Interface { return eventing.New(f, f.namespace, f.tweakListOptions) } + +func (f *sharedInformerFactory) Sources() sources.Interface { + return sources.New(f, f.namespace, f.tweakListOptions) +} diff --git a/pkg/client/informers/externalversions/generic.go b/pkg/client/informers/externalversions/generic.go index 6c22f720af9..2477bdb6c07 100644 --- a/pkg/client/informers/externalversions/generic.go +++ b/pkg/client/informers/externalversions/generic.go @@ -22,6 +22,7 @@ import ( "fmt" v1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" + sourcesv1alpha1 "github.com/knative/eventing/pkg/apis/sources/v1alpha1" schema "k8s.io/apimachinery/pkg/runtime/schema" cache "k8s.io/client-go/tools/cache" ) @@ -64,6 +65,10 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource case v1alpha1.SchemeGroupVersion.WithResource("triggers"): return &genericInformer{resource: resource.GroupResource(), informer: f.Eventing().V1alpha1().Triggers().Informer()}, nil + // Group=sources.eventing.knative.dev, Version=v1alpha1 + case sourcesv1alpha1.SchemeGroupVersion.WithResource("cronjobsources"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Sources().V1alpha1().CronJobSources().Informer()}, nil + } return nil, fmt.Errorf("no informer found for %v", resource) diff --git a/pkg/client/informers/externalversions/sources/interface.go b/pkg/client/informers/externalversions/sources/interface.go new file mode 100644 index 00000000000..654f1938531 --- /dev/null +++ b/pkg/client/informers/externalversions/sources/interface.go @@ -0,0 +1,46 @@ +/* +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 sources + +import ( + internalinterfaces "github.com/knative/eventing/pkg/client/informers/externalversions/internalinterfaces" + v1alpha1 "github.com/knative/eventing/pkg/client/informers/externalversions/sources/v1alpha1" +) + +// Interface provides access to each of this group's versions. +type Interface interface { + // V1alpha1 provides access to shared informers for resources in V1alpha1. + V1alpha1() v1alpha1.Interface +} + +type group struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// V1alpha1 returns a new v1alpha1.Interface. +func (g *group) V1alpha1() v1alpha1.Interface { + return v1alpha1.New(g.factory, g.namespace, g.tweakListOptions) +} diff --git a/pkg/client/informers/externalversions/sources/v1alpha1/cronjobsource.go b/pkg/client/informers/externalversions/sources/v1alpha1/cronjobsource.go new file mode 100644 index 00000000000..c05b7692e5a --- /dev/null +++ b/pkg/client/informers/externalversions/sources/v1alpha1/cronjobsource.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" + + sourcesv1alpha1 "github.com/knative/eventing/pkg/apis/sources/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/sources/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" +) + +// CronJobSourceInformer provides access to a shared informer and lister for +// CronJobSources. +type CronJobSourceInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1alpha1.CronJobSourceLister +} + +type cronJobSourceInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewCronJobSourceInformer constructs a new informer for CronJobSource 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 NewCronJobSourceInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredCronJobSourceInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredCronJobSourceInformer constructs a new informer for CronJobSource 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 NewFilteredCronJobSourceInformer(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.SourcesV1alpha1().CronJobSources(namespace).List(options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.SourcesV1alpha1().CronJobSources(namespace).Watch(options) + }, + }, + &sourcesv1alpha1.CronJobSource{}, + resyncPeriod, + indexers, + ) +} + +func (f *cronJobSourceInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredCronJobSourceInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *cronJobSourceInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&sourcesv1alpha1.CronJobSource{}, f.defaultInformer) +} + +func (f *cronJobSourceInformer) Lister() v1alpha1.CronJobSourceLister { + return v1alpha1.NewCronJobSourceLister(f.Informer().GetIndexer()) +} diff --git a/pkg/client/informers/externalversions/sources/v1alpha1/interface.go b/pkg/client/informers/externalversions/sources/v1alpha1/interface.go new file mode 100644 index 00000000000..cf621f01e7e --- /dev/null +++ b/pkg/client/informers/externalversions/sources/v1alpha1/interface.go @@ -0,0 +1,45 @@ +/* +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 ( + internalinterfaces "github.com/knative/eventing/pkg/client/informers/externalversions/internalinterfaces" +) + +// Interface provides access to all the informers in this group version. +type Interface interface { + // CronJobSources returns a CronJobSourceInformer. + CronJobSources() CronJobSourceInformer +} + +type version struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// CronJobSources returns a CronJobSourceInformer. +func (v *version) CronJobSources() CronJobSourceInformer { + return &cronJobSourceInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} diff --git a/pkg/client/listers/sources/v1alpha1/cronjobsource.go b/pkg/client/listers/sources/v1alpha1/cronjobsource.go new file mode 100644 index 00000000000..4c4d43bcfac --- /dev/null +++ b/pkg/client/listers/sources/v1alpha1/cronjobsource.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/sources/v1alpha1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" +) + +// CronJobSourceLister helps list CronJobSources. +type CronJobSourceLister interface { + // List lists all CronJobSources in the indexer. + List(selector labels.Selector) (ret []*v1alpha1.CronJobSource, err error) + // CronJobSources returns an object that can list and get CronJobSources. + CronJobSources(namespace string) CronJobSourceNamespaceLister + CronJobSourceListerExpansion +} + +// cronJobSourceLister implements the CronJobSourceLister interface. +type cronJobSourceLister struct { + indexer cache.Indexer +} + +// NewCronJobSourceLister returns a new CronJobSourceLister. +func NewCronJobSourceLister(indexer cache.Indexer) CronJobSourceLister { + return &cronJobSourceLister{indexer: indexer} +} + +// List lists all CronJobSources in the indexer. +func (s *cronJobSourceLister) List(selector labels.Selector) (ret []*v1alpha1.CronJobSource, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.CronJobSource)) + }) + return ret, err +} + +// CronJobSources returns an object that can list and get CronJobSources. +func (s *cronJobSourceLister) CronJobSources(namespace string) CronJobSourceNamespaceLister { + return cronJobSourceNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// CronJobSourceNamespaceLister helps list and get CronJobSources. +type CronJobSourceNamespaceLister interface { + // List lists all CronJobSources in the indexer for a given namespace. + List(selector labels.Selector) (ret []*v1alpha1.CronJobSource, err error) + // Get retrieves the CronJobSource from the indexer for a given namespace and name. + Get(name string) (*v1alpha1.CronJobSource, error) + CronJobSourceNamespaceListerExpansion +} + +// cronJobSourceNamespaceLister implements the CronJobSourceNamespaceLister +// interface. +type cronJobSourceNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all CronJobSources in the indexer for a given namespace. +func (s cronJobSourceNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.CronJobSource, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.CronJobSource)) + }) + return ret, err +} + +// Get retrieves the CronJobSource from the indexer for a given namespace and name. +func (s cronJobSourceNamespaceLister) Get(name string) (*v1alpha1.CronJobSource, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1alpha1.Resource("cronjobsource"), name) + } + return obj.(*v1alpha1.CronJobSource), nil +} diff --git a/pkg/client/listers/sources/v1alpha1/expansion_generated.go b/pkg/client/listers/sources/v1alpha1/expansion_generated.go new file mode 100644 index 00000000000..f9b1368c856 --- /dev/null +++ b/pkg/client/listers/sources/v1alpha1/expansion_generated.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. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha1 + +// CronJobSourceListerExpansion allows custom methods to be added to +// CronJobSourceLister. +type CronJobSourceListerExpansion interface{} + +// CronJobSourceNamespaceListerExpansion allows custom methods to be added to +// CronJobSourceNamespaceLister. +type CronJobSourceNamespaceListerExpansion interface{} From 0f3fa9fe90e388f019465b2b0ec88886040d6386 Mon Sep 17 00:00:00 2001 From: Scott Nichols Date: Tue, 23 Apr 2019 10:57:48 -0700 Subject: [PATCH 04/25] ported rec. --- Gopkg.lock | 14 +- cmd/cronjob_receive_adapter/main.go | 74 ++ config/500-controller.yaml | 2 + hack/update-codegen.sh | 5 - pkg/apis/sources/v1alpha1/cron_job_types.go | 10 + pkg/client/clientset/versioned/clientset.go | 24 +- .../versioned/fake/clientset_generated.go | 12 + .../clientset/versioned/fake/register.go | 2 + .../clientset/versioned/scheme/register.go | 2 + .../informers/externalversions/factory.go | 6 + .../informers/externalversions/generic.go | 19 +- .../controller/sinks => pkg/duck}/sinks.go | 21 +- pkg/duck/sinks_test.go | 210 ++++++ pkg/{utils/resolve => duck}/subscriber.go | 2 +- .../resolve => duck}/subscriber_test.go | 6 +- .../containersource/containersource.go | 253 ------- .../containersource/containersource_test.go | 642 ------------------ .../containersource/resources/arguments.go | 34 - .../containersource/resources/deployment.go | 115 ---- .../resources/deployment_test.go | 292 -------- pkg/reconciler/cronjobsource/cronjobsource.go | 278 ++++++++ .../cronjobsource/cronjobsource_test.go | 325 +++++++++ .../{containersource => cronjobsource}/doc.go | 6 +- .../cronjobsource/resources/labels.go | 24 +- .../resources/receive_adapter.go | 90 +++ .../resources/receive_adapter_test.go | 111 +++ pkg/reconciler/subscription/subscription.go | 28 +- pkg/reconciler/v1alpha1/trigger/trigger.go | 4 +- third_party/VENDOR-LICENSE | 234 +++++++ .../containersource/resources/deployment.go | 115 ---- .../controllerutil/controllerutil.go | 178 ----- .../pkg/controller/controllerutil/doc.go | 20 - 32 files changed, 1444 insertions(+), 1714 deletions(-) create mode 100644 cmd/cronjob_receive_adapter/main.go rename {vendor/github.com/knative/eventing-sources/pkg/controller/sinks => pkg/duck}/sinks.go (74%) create mode 100644 pkg/duck/sinks_test.go rename pkg/{utils/resolve => duck}/subscriber.go (99%) rename pkg/{utils/resolve => duck}/subscriber_test.go (99%) delete mode 100644 pkg/reconciler/containersource/containersource.go delete mode 100644 pkg/reconciler/containersource/containersource_test.go delete mode 100644 pkg/reconciler/containersource/resources/arguments.go delete mode 100644 pkg/reconciler/containersource/resources/deployment.go delete mode 100644 pkg/reconciler/containersource/resources/deployment_test.go create mode 100644 pkg/reconciler/cronjobsource/cronjobsource.go create mode 100644 pkg/reconciler/cronjobsource/cronjobsource_test.go rename pkg/reconciler/{containersource => cronjobsource}/doc.go (80%) rename vendor/github.com/knative/eventing-sources/pkg/reconciler/containersource/resources/arguments.go => pkg/reconciler/cronjobsource/resources/labels.go (57%) create mode 100644 pkg/reconciler/cronjobsource/resources/receive_adapter.go create mode 100644 pkg/reconciler/cronjobsource/resources/receive_adapter_test.go delete mode 100644 vendor/github.com/knative/eventing-sources/pkg/reconciler/containersource/resources/deployment.go delete mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/controller/controllerutil/controllerutil.go delete mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/controller/controllerutil/doc.go diff --git a/Gopkg.lock b/Gopkg.lock index 85e814985d6..4a216127e60 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -425,15 +425,13 @@ revision = "f2b4162afba35581b6d4a50d3b8f34e33c144682" [[projects]] - digest = "1:94171d9b3c7cfea54e726005e58044a2325ccf796ecf4bf025a3d20a1e145fba" + digest = "1:5923fb20c8ac5e5dcc2e7a9f8dfa702c72491f3905372454add6cbb59b0e39fb" name = "github.com/knative/eventing-sources" packages = [ "pkg/apis/sources/v1alpha1", "pkg/controller/sdk", - "pkg/controller/sinks", "pkg/controller/testing", "pkg/kncloudevents", - "pkg/reconciler/containersource/resources", ] pruneopts = "NUT" revision = "32ce3778fa1bc46ed0b0ade16d5c57f343cafa4d" @@ -1336,7 +1334,7 @@ revision = "8a9b82f00b3a86eac24681da3f9fe6c34c01cea2" [[projects]] - digest = "1:399953e7c3ac9253dcf1fe909b0a74f6d1c4e974decefd6f5d361cab06249ccc" + digest = "1:b96e8e4a7931b07c33fdb206bfc4d27273bd599e48061500138ed69303388140" name = "sigs.k8s.io/controller-runtime" packages = [ "pkg/cache", @@ -1346,7 +1344,6 @@ "pkg/client/config", "pkg/client/fake", "pkg/controller", - "pkg/controller/controllerutil", "pkg/event", "pkg/handler", "pkg/internal/controller", @@ -1391,11 +1388,8 @@ "github.com/google/go-cmp/cmp/cmpopts", "github.com/google/uuid", "github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1", - "github.com/knative/eventing-sources/pkg/controller/sdk", - "github.com/knative/eventing-sources/pkg/controller/sinks", "github.com/knative/eventing-sources/pkg/controller/testing", "github.com/knative/eventing-sources/pkg/kncloudevents", - "github.com/knative/eventing-sources/pkg/reconciler/containersource/resources", "github.com/knative/pkg/apis", "github.com/knative/pkg/apis/duck", "github.com/knative/pkg/apis/duck/v1alpha1", @@ -1404,6 +1398,7 @@ "github.com/knative/pkg/client/listers/istio/v1alpha3", "github.com/knative/pkg/configmap", "github.com/knative/pkg/controller", + "github.com/knative/pkg/kmeta", "github.com/knative/pkg/kmp", "github.com/knative/pkg/logging", "github.com/knative/pkg/logging/logkey", @@ -1430,6 +1425,7 @@ "go.uber.org/zap", "go.uber.org/zap/zapcore", "go.uber.org/zap/zaptest/observer", + "golang.org/x/net/context", "golang.org/x/oauth2/google", "google.golang.org/api/option", "gopkg.in/yaml.v2", @@ -1459,6 +1455,7 @@ "k8s.io/client-go/dynamic", "k8s.io/client-go/dynamic/fake", "k8s.io/client-go/informers", + "k8s.io/client-go/informers/apps/v1", "k8s.io/client-go/kubernetes", "k8s.io/client-go/kubernetes/fake", "k8s.io/client-go/kubernetes/scheme", @@ -1482,7 +1479,6 @@ "sigs.k8s.io/controller-runtime/pkg/client/config", "sigs.k8s.io/controller-runtime/pkg/client/fake", "sigs.k8s.io/controller-runtime/pkg/controller", - "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil", "sigs.k8s.io/controller-runtime/pkg/event", "sigs.k8s.io/controller-runtime/pkg/handler", "sigs.k8s.io/controller-runtime/pkg/manager", diff --git a/cmd/cronjob_receive_adapter/main.go b/cmd/cronjob_receive_adapter/main.go new file mode 100644 index 00000000000..965ad2af176 --- /dev/null +++ b/cmd/cronjob_receive_adapter/main.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 main + +import ( + "flag" + "log" + "os" + + "github.com/knative/eventing/pkg/adapter/cronjobevents" + "github.com/knative/pkg/signals" + "go.uber.org/zap" + "go.uber.org/zap/zapcore" + "golang.org/x/net/context" +) + +const ( + // Environment variable container schedule. + envSchedule = "SCHEDULE" + + // Environment variable containing data. + envData = "DATA" + + // Sink for messages. + envSinkURI = "SINK_URI" +) + +func getRequiredEnv(envKey string) string { + val, defined := os.LookupEnv(envKey) + if !defined { + log.Fatalf("required environment variable not defined %q", envKey) + } + return val +} + +func main() { + flag.Parse() + + ctx := context.Background() + logCfg := zap.NewProductionConfig() + logCfg.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder + logger, err := logCfg.Build() + if err != nil { + log.Fatalf("Unable to create logger: %v", err) + } + + adapter := &cronjobevents.Adapter{ + Schedule: getRequiredEnv(envSchedule), + Data: getRequiredEnv(envData), + SinkURI: getRequiredEnv(envSinkURI), + } + + logger.Info("Starting Receive Adapter", zap.Reflect("adapter", adapter)) + + stopCh := signals.SetupSignalHandler() + + if err := adapter.Start(ctx, stopCh); err != nil { + logger.Fatal("Failed to start adapter", zap.Error(err)) + } +} diff --git a/config/500-controller.yaml b/config/500-controller.yaml index f1466e1a55a..e28a2633725 100644 --- a/config/500-controller.yaml +++ b/config/500-controller.yaml @@ -49,6 +49,8 @@ spec: value: github.com/knative/eventing/cmd/broker/filter - name: BROKER_FILTER_SERVICE_ACCOUNT value: eventing-broker-filter + - name: CRONJOB_RA_IMAGE + value: github.com/knative/eventing/cmd/cronjob_receive_adapter ports: - containerPort: 9090 name: metrics diff --git a/hack/update-codegen.sh b/hack/update-codegen.sh index d51d48dba55..dea5391fec7 100755 --- a/hack/update-codegen.sh +++ b/hack/update-codegen.sh @@ -31,11 +31,6 @@ ${CODEGEN_PKG}/generate-groups.sh "deepcopy,client,informer,lister" \ "eventing:v1alpha1 sources:v1alpha1" \ --go-header-file ${REPO_ROOT_DIR}/hack/boilerplate/boilerplate.go.txt -${CODEGEN_PKG}/generate-groups.sh "deepcopy,client,informer,lister" \ - github.com/knative/eventing/pkg/client github.com/knative/eventing/pkg/apis \ - "sources:v1alpha1" \ - --go-header-file ${REPO_ROOT_DIR}/hack/boilerplate/boilerplate.go.txt - # Only deepcopy the Duck types, as they are not real resources. ${CODEGEN_PKG}/generate-groups.sh "deepcopy" \ github.com/knative/eventing/pkg/client github.com/knative/eventing/pkg/apis \ diff --git a/pkg/apis/sources/v1alpha1/cron_job_types.go b/pkg/apis/sources/v1alpha1/cron_job_types.go index df6f69d9197..4308730c295 100644 --- a/pkg/apis/sources/v1alpha1/cron_job_types.go +++ b/pkg/apis/sources/v1alpha1/cron_job_types.go @@ -19,9 +19,11 @@ package v1alpha1 import ( "github.com/knative/pkg/apis/duck" duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" + "github.com/knative/pkg/kmeta" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" ) // +genclient @@ -39,6 +41,9 @@ type CronJobSource struct { // Check that CronJobSource can be validated and can be defaulted. var _ runtime.Object = (*CronJobSource)(nil) +// Check that we can create OwnerReferences to a Configuration. +var _ kmeta.OwnerRefable = (*CronJobSource)(nil) + // Check that CronJobSource implements the Conditions duck type. var _ = duck.VerifyType(&CronJobSource{}, &duckv1alpha1.Conditions{}) @@ -61,6 +66,11 @@ type CronJobSourceSpec struct { ServiceAccountName string `json:"serviceAccountName,omitempty"` } +// GetGroupVersionKind returns the GroupVersionKind. +func (s *CronJobSource) GetGroupVersionKind() schema.GroupVersionKind { + return SchemeGroupVersion.WithKind("CronJobSource") +} + // CronJobSourceStatus defines the observed state of CronJobSource. type CronJobSourceStatus struct { // inherits duck/v1alpha1 Status, which currently provides: diff --git a/pkg/client/clientset/versioned/clientset.go b/pkg/client/clientset/versioned/clientset.go index 37423028552..1c27aed4eb5 100644 --- a/pkg/client/clientset/versioned/clientset.go +++ b/pkg/client/clientset/versioned/clientset.go @@ -19,6 +19,7 @@ limitations under the License. package versioned import ( + eventingv1alpha1 "github.com/knative/eventing/pkg/client/clientset/versioned/typed/eventing/v1alpha1" sourcesv1alpha1 "github.com/knative/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha1" discovery "k8s.io/client-go/discovery" rest "k8s.io/client-go/rest" @@ -27,6 +28,9 @@ import ( type Interface interface { Discovery() discovery.DiscoveryInterface + EventingV1alpha1() eventingv1alpha1.EventingV1alpha1Interface + // Deprecated: please explicitly pick a version if possible. + Eventing() eventingv1alpha1.EventingV1alpha1Interface SourcesV1alpha1() sourcesv1alpha1.SourcesV1alpha1Interface // Deprecated: please explicitly pick a version if possible. Sources() sourcesv1alpha1.SourcesV1alpha1Interface @@ -36,7 +40,19 @@ type Interface interface { // version included in a Clientset. type Clientset struct { *discovery.DiscoveryClient - sourcesV1alpha1 *sourcesv1alpha1.SourcesV1alpha1Client + eventingV1alpha1 *eventingv1alpha1.EventingV1alpha1Client + sourcesV1alpha1 *sourcesv1alpha1.SourcesV1alpha1Client +} + +// EventingV1alpha1 retrieves the EventingV1alpha1Client +func (c *Clientset) EventingV1alpha1() eventingv1alpha1.EventingV1alpha1Interface { + return c.eventingV1alpha1 +} + +// Deprecated: Eventing retrieves the default version of EventingClient. +// Please explicitly pick a version. +func (c *Clientset) Eventing() eventingv1alpha1.EventingV1alpha1Interface { + return c.eventingV1alpha1 } // SourcesV1alpha1 retrieves the SourcesV1alpha1Client @@ -66,6 +82,10 @@ func NewForConfig(c *rest.Config) (*Clientset, error) { } var cs Clientset var err error + cs.eventingV1alpha1, err = eventingv1alpha1.NewForConfig(&configShallowCopy) + if err != nil { + return nil, err + } cs.sourcesV1alpha1, err = sourcesv1alpha1.NewForConfig(&configShallowCopy) if err != nil { return nil, err @@ -82,6 +102,7 @@ func NewForConfig(c *rest.Config) (*Clientset, error) { // panics if there is an error in the config. func NewForConfigOrDie(c *rest.Config) *Clientset { var cs Clientset + cs.eventingV1alpha1 = eventingv1alpha1.NewForConfigOrDie(c) cs.sourcesV1alpha1 = sourcesv1alpha1.NewForConfigOrDie(c) cs.DiscoveryClient = discovery.NewDiscoveryClientForConfigOrDie(c) @@ -91,6 +112,7 @@ func NewForConfigOrDie(c *rest.Config) *Clientset { // New creates a new Clientset for the given RESTClient. func New(c rest.Interface) *Clientset { var cs Clientset + cs.eventingV1alpha1 = eventingv1alpha1.New(c) cs.sourcesV1alpha1 = sourcesv1alpha1.New(c) cs.DiscoveryClient = discovery.NewDiscoveryClient(c) diff --git a/pkg/client/clientset/versioned/fake/clientset_generated.go b/pkg/client/clientset/versioned/fake/clientset_generated.go index 4f40e6e25fe..c539ac22f55 100644 --- a/pkg/client/clientset/versioned/fake/clientset_generated.go +++ b/pkg/client/clientset/versioned/fake/clientset_generated.go @@ -20,6 +20,8 @@ package fake import ( clientset "github.com/knative/eventing/pkg/client/clientset/versioned" + eventingv1alpha1 "github.com/knative/eventing/pkg/client/clientset/versioned/typed/eventing/v1alpha1" + fakeeventingv1alpha1 "github.com/knative/eventing/pkg/client/clientset/versioned/typed/eventing/v1alpha1/fake" sourcesv1alpha1 "github.com/knative/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha1" fakesourcesv1alpha1 "github.com/knative/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha1/fake" "k8s.io/apimachinery/pkg/runtime" @@ -71,6 +73,16 @@ func (c *Clientset) Discovery() discovery.DiscoveryInterface { var _ clientset.Interface = &Clientset{} +// EventingV1alpha1 retrieves the EventingV1alpha1Client +func (c *Clientset) EventingV1alpha1() eventingv1alpha1.EventingV1alpha1Interface { + return &fakeeventingv1alpha1.FakeEventingV1alpha1{Fake: &c.Fake} +} + +// Eventing retrieves the EventingV1alpha1Client +func (c *Clientset) Eventing() eventingv1alpha1.EventingV1alpha1Interface { + return &fakeeventingv1alpha1.FakeEventingV1alpha1{Fake: &c.Fake} +} + // SourcesV1alpha1 retrieves the SourcesV1alpha1Client func (c *Clientset) SourcesV1alpha1() sourcesv1alpha1.SourcesV1alpha1Interface { return &fakesourcesv1alpha1.FakeSourcesV1alpha1{Fake: &c.Fake} diff --git a/pkg/client/clientset/versioned/fake/register.go b/pkg/client/clientset/versioned/fake/register.go index 325188a8adf..5d1afb6a6e2 100644 --- a/pkg/client/clientset/versioned/fake/register.go +++ b/pkg/client/clientset/versioned/fake/register.go @@ -19,6 +19,7 @@ limitations under the License. package fake import ( + eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" sourcesv1alpha1 "github.com/knative/eventing/pkg/apis/sources/v1alpha1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" @@ -31,6 +32,7 @@ var scheme = runtime.NewScheme() var codecs = serializer.NewCodecFactory(scheme) var parameterCodec = runtime.NewParameterCodec(scheme) var localSchemeBuilder = runtime.SchemeBuilder{ + eventingv1alpha1.AddToScheme, sourcesv1alpha1.AddToScheme, } diff --git a/pkg/client/clientset/versioned/scheme/register.go b/pkg/client/clientset/versioned/scheme/register.go index b0dd52f43ba..639371bf1db 100644 --- a/pkg/client/clientset/versioned/scheme/register.go +++ b/pkg/client/clientset/versioned/scheme/register.go @@ -19,6 +19,7 @@ limitations under the License. package scheme import ( + eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" sourcesv1alpha1 "github.com/knative/eventing/pkg/apis/sources/v1alpha1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" @@ -31,6 +32,7 @@ var Scheme = runtime.NewScheme() var Codecs = serializer.NewCodecFactory(Scheme) var ParameterCodec = runtime.NewParameterCodec(Scheme) var localSchemeBuilder = runtime.SchemeBuilder{ + eventingv1alpha1.AddToScheme, sourcesv1alpha1.AddToScheme, } diff --git a/pkg/client/informers/externalversions/factory.go b/pkg/client/informers/externalversions/factory.go index 90878bd75fe..51a86f08730 100644 --- a/pkg/client/informers/externalversions/factory.go +++ b/pkg/client/informers/externalversions/factory.go @@ -24,6 +24,7 @@ import ( time "time" versioned "github.com/knative/eventing/pkg/client/clientset/versioned" + eventing "github.com/knative/eventing/pkg/client/informers/externalversions/eventing" internalinterfaces "github.com/knative/eventing/pkg/client/informers/externalversions/internalinterfaces" sources "github.com/knative/eventing/pkg/client/informers/externalversions/sources" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -172,9 +173,14 @@ type SharedInformerFactory interface { ForResource(resource schema.GroupVersionResource) (GenericInformer, error) WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool + Eventing() eventing.Interface Sources() sources.Interface } +func (f *sharedInformerFactory) Eventing() eventing.Interface { + return eventing.New(f, f.namespace, f.tweakListOptions) +} + func (f *sharedInformerFactory) Sources() sources.Interface { return sources.New(f, f.namespace, f.tweakListOptions) } diff --git a/pkg/client/informers/externalversions/generic.go b/pkg/client/informers/externalversions/generic.go index 8a1014ec955..2477bdb6c07 100644 --- a/pkg/client/informers/externalversions/generic.go +++ b/pkg/client/informers/externalversions/generic.go @@ -21,7 +21,8 @@ package externalversions import ( "fmt" - v1alpha1 "github.com/knative/eventing/pkg/apis/sources/v1alpha1" + v1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" + sourcesv1alpha1 "github.com/knative/eventing/pkg/apis/sources/v1alpha1" schema "k8s.io/apimachinery/pkg/runtime/schema" cache "k8s.io/client-go/tools/cache" ) @@ -52,8 +53,20 @@ func (f *genericInformer) Lister() cache.GenericLister { // TODO extend this to unknown resources with a client pool func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) { switch resource { - // Group=sources.eventing.knative.dev, Version=v1alpha1 - case v1alpha1.SchemeGroupVersion.WithResource("cronjobsources"): + // 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"): + 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 + + // Group=sources.eventing.knative.dev, Version=v1alpha1 + case sourcesv1alpha1.SchemeGroupVersion.WithResource("cronjobsources"): return &genericInformer{resource: resource.GroupResource(), informer: f.Sources().V1alpha1().CronJobSources().Informer()}, nil } diff --git a/vendor/github.com/knative/eventing-sources/pkg/controller/sinks/sinks.go b/pkg/duck/sinks.go similarity index 74% rename from vendor/github.com/knative/eventing-sources/pkg/controller/sinks/sinks.go rename to pkg/duck/sinks.go index 4e87c3ac013..e5a83686d94 100644 --- a/vendor/github.com/knative/eventing-sources/pkg/controller/sinks/sinks.go +++ b/pkg/duck/sinks.go @@ -14,29 +14,34 @@ See the License for the specific language governing permissions and limitations under the License. */ -package sinks +package duck import ( "context" "fmt" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/dynamic" + + duckapis "github.com/knative/pkg/apis" "github.com/knative/pkg/apis/duck" duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "sigs.k8s.io/controller-runtime/pkg/client" ) // GetSinkURI retrieves the sink URI from the object referenced by the given // ObjectReference. -func GetSinkURI(ctx context.Context, c client.Client, sink *corev1.ObjectReference, namespace string) (string, error) { +func GetSinkURI(ctx context.Context, dynamicClient dynamic.Interface, sink *corev1.ObjectReference, namespace string) (string, error) { if sink == nil { return "", fmt.Errorf("sink ref is nil") } - u := &unstructured.Unstructured{} - u.SetGroupVersionKind(sink.GroupVersionKind()) - err := c.Get(ctx, client.ObjectKey{Namespace: namespace, Name: sink.Name}, u) + rc := dynamicClient.Resource(duckapis.KindToResource(sink.GroupVersionKind())) + if rc == nil { + return "", fmt.Errorf("failed to create dynamic client resource") + } + + u, err := rc.Namespace(namespace).Get(sink.Name, metav1.GetOptions{}) if err != nil { return "", err } diff --git a/pkg/duck/sinks_test.go b/pkg/duck/sinks_test.go new file mode 100644 index 00000000000..e52c94ce742 --- /dev/null +++ b/pkg/duck/sinks_test.go @@ -0,0 +1,210 @@ +/* +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 duck + +import ( + "context" + "fmt" + "testing" + + "github.com/google/go-cmp/cmp" + duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/dynamic/fake" + "k8s.io/client-go/kubernetes/scheme" +) + +var ( + addressableDNS = "addressable.sink.svc.cluster.local" + + addressableName = "testsink" + addressableKind = "Sink" + addressableAPIVersion = "duck.knative.dev/v1alpha1" + + unaddressableName = "testunaddressable" + unaddressableKind = "KResource" + unaddressableAPIVersion = "duck.knative.dev/v1alpha1" + unaddressableResource = "kresources.duck.knative.dev" + + testNS = "testnamespace" +) + +func init() { + // Add types to scheme + duckv1alpha1.AddToScheme(scheme.Scheme) +} + +func TestGetSinkURI(t *testing.T) { + testCases := map[string]struct { + objects []runtime.Object + namespace string + want string + wantErr error + ref *corev1.ObjectReference + }{ + "happy": { + objects: []runtime.Object{ + getAddressable(), + }, + namespace: testNS, + ref: getAddressableRef(), + want: fmt.Sprintf("http://%s/", addressableDNS), + }, + "nil hostname": { + objects: []runtime.Object{ + getAddressableNilHostname(), + }, + namespace: testNS, + ref: getUnaddressableRef(), + wantErr: fmt.Errorf(`sink "testnamespace/testunaddressable" (duck.knative.dev/v1alpha1, Kind=KResource) contains an empty hostname`), + }, + "nil sink": { + objects: []runtime.Object{ + getAddressableNilHostname(), + }, + namespace: testNS, + ref: nil, + wantErr: fmt.Errorf(`sink ref is nil`), + }, + "nil address": { + objects: []runtime.Object{ + getAddressableNilAddress(), + }, + namespace: testNS, + ref: nil, + wantErr: fmt.Errorf(`sink ref is nil`), + }, + "notSink": { + objects: []runtime.Object{ + getAddressableNoStatus(), + }, + namespace: testNS, + ref: getUnaddressableRef(), + wantErr: fmt.Errorf(`sink "testnamespace/testunaddressable" (duck.knative.dev/v1alpha1, Kind=KResource) does not contain address`), + }, + "notFound": { + namespace: testNS, + ref: getUnaddressableRef(), + wantErr: fmt.Errorf(`%s "%s" not found`, unaddressableResource, unaddressableName), + }, + } + for n, tc := range testCases { + t.Run(n, func(t *testing.T) { + ctx := context.Background() + client := fake.NewSimpleDynamicClient(scheme.Scheme, tc.objects...) + uri, gotErr := GetSinkURI(ctx, client, tc.ref, tc.namespace) + if gotErr != nil { + if tc.wantErr != nil { + if diff := cmp.Diff(tc.wantErr.Error(), gotErr.Error()); diff != "" { + t.Errorf("%s: unexpected error (-want, +got) = %v", n, diff) + } + } else { + t.Errorf("%s: unexpected error %v", n, gotErr.Error()) + } + } + if gotErr == nil { + got := uri + if diff := cmp.Diff(tc.want, got); diff != "" { + t.Errorf("%s: unexpected object (-want, +got) = %v", n, diff) + } + } + }) + } +} + +func getAddressable() *unstructured.Unstructured { + return &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": addressableAPIVersion, + "kind": addressableKind, + "metadata": map[string]interface{}{ + "namespace": testNS, + "name": addressableName, + }, + "status": map[string]interface{}{ + "address": map[string]interface{}{ + "hostname": addressableDNS, + }, + }, + }, + } +} + +func getAddressableNoStatus() *unstructured.Unstructured { + return &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": unaddressableAPIVersion, + "kind": unaddressableKind, + "metadata": map[string]interface{}{ + "namespace": testNS, + "name": unaddressableName, + }, + }, + } +} + +func getAddressableNilAddress() *unstructured.Unstructured { + return &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": unaddressableAPIVersion, + "kind": unaddressableKind, + "metadata": map[string]interface{}{ + "namespace": testNS, + "name": unaddressableName, + }, + "status": map[string]interface{}{ + "address": map[string]interface{}(nil), + }, + }, + } +} + +func getAddressableNilHostname() *unstructured.Unstructured { + return &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": unaddressableAPIVersion, + "kind": unaddressableKind, + "metadata": map[string]interface{}{ + "namespace": testNS, + "name": unaddressableName, + }, + "status": map[string]interface{}{ + "address": map[string]interface{}{ + "hostname": nil, + }, + }, + }, + } +} + +func getAddressableRef() *corev1.ObjectReference { + return &corev1.ObjectReference{ + Kind: addressableKind, + Name: addressableName, + APIVersion: addressableAPIVersion, + } +} + +func getUnaddressableRef() *corev1.ObjectReference { + return &corev1.ObjectReference{ + Kind: unaddressableKind, + Name: unaddressableName, + APIVersion: unaddressableAPIVersion, + } +} diff --git a/pkg/utils/resolve/subscriber.go b/pkg/duck/subscriber.go similarity index 99% rename from pkg/utils/resolve/subscriber.go rename to pkg/duck/subscriber.go index 8fa5a3c47a0..9458868234b 100644 --- a/pkg/utils/resolve/subscriber.go +++ b/pkg/duck/subscriber.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package resolve +package duck import ( "context" diff --git a/pkg/utils/resolve/subscriber_test.go b/pkg/duck/subscriber_test.go similarity index 99% rename from pkg/utils/resolve/subscriber_test.go rename to pkg/duck/subscriber_test.go index ec13a4f5fab..2ede971e1f1 100644 --- a/pkg/utils/resolve/subscriber_test.go +++ b/pkg/duck/subscriber_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package resolve +package duck import ( "context" @@ -35,10 +35,6 @@ import ( "k8s.io/client-go/kubernetes/scheme" ) -const ( - testNS = "test-namespace" -) - var ( uri = "http://example.com" diff --git a/pkg/reconciler/containersource/containersource.go b/pkg/reconciler/containersource/containersource.go deleted file mode 100644 index 87cd1a8b705..00000000000 --- a/pkg/reconciler/containersource/containersource.go +++ /dev/null @@ -1,253 +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 containersource - -import ( - "context" - "fmt" - "strings" - - "github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1" - "github.com/knative/eventing-sources/pkg/controller/sdk" - "github.com/knative/eventing-sources/pkg/controller/sinks" - "github.com/knative/eventing-sources/pkg/reconciler/containersource/resources" - "github.com/knative/pkg/logging" - "go.uber.org/zap" - appsv1 "k8s.io/api/apps/v1" - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/equality" - "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/api/meta" - 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/client-go/tools/record" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" - "sigs.k8s.io/controller-runtime/pkg/manager" -) - -const ( - // controllerAgentName is the string used by this controller to identify - // itself when creating events. - controllerAgentName = "container-source-controller" -) - -// Add creates a new ContainerSource Controller and adds it to the Manager with -// default RBAC. The Manager will set fields on the Controller and Start it when -// the Manager is Started. -func Add(mgr manager.Manager, logger *zap.SugaredLogger) error { - p := &sdk.Provider{ - AgentName: controllerAgentName, - Parent: &v1alpha1.ContainerSource{}, - Owns: []runtime.Object{&appsv1.Deployment{}}, - Reconciler: &reconciler{ - recorder: mgr.GetRecorder(controllerAgentName), - scheme: mgr.GetScheme(), - }, - } - - return p.Add(mgr, logger) -} - -type reconciler struct { - client client.Client - scheme *runtime.Scheme - recorder record.EventRecorder -} - -// Reconcile compares the actual state with the desired, and attempts to -// converge the two. -func (r *reconciler) Reconcile(ctx context.Context, object runtime.Object) error { - logger := logging.FromContext(ctx) - - source, ok := object.(*v1alpha1.ContainerSource) - if !ok { - logger.Errorf("could not find container source %v\n", object) - return nil - } - - // See if the source has been deleted - accessor, err := meta.Accessor(source) - if err != nil { - logger.Warnf("Failed to get metadata accessor: %s", zap.Error(err)) - return err - } - // No need to reconcile if the source has been marked for deletion. - deletionTimestamp := accessor.GetDeletionTimestamp() - if deletionTimestamp != nil { - return nil - } - - source.Status.InitializeConditions() - - annotations := make(map[string]string) - // Then wire through any annotations / labels from the Source - if source.ObjectMeta.Annotations != nil { - for k, v := range source.ObjectMeta.Annotations { - annotations[k] = v - } - } - labels := make(map[string]string) - if source.ObjectMeta.Labels != nil { - for k, v := range source.ObjectMeta.Labels { - labels[k] = v - } - } - - args := &resources.ContainerArguments{ - Name: source.Name, - Namespace: source.Namespace, - Image: source.Spec.Image, - Args: source.Spec.Args, - Env: source.Spec.Env, - ServiceAccountName: source.Spec.ServiceAccountName, - Annotations: annotations, - Labels: labels, - } - - err = r.setSinkURIArg(ctx, source, args) - if err != nil { - return err - } - - deploy, err := r.getDeployment(ctx, source) - if err != nil { - if errors.IsNotFound(err) { - deploy, err = r.createDeployment(ctx, source, nil, args) - if err != nil { - r.recorder.Eventf(source, corev1.EventTypeNormal, "DeploymentBlocked", "waiting for %v", err) - return err - } - r.recorder.Eventf(source, corev1.EventTypeNormal, "Deployed", "Created deployment %q", deploy.Name) - source.Status.MarkDeploying("Deploying", "Created deployment %s", deploy.Name) - // Since the Deployment has just been created, there's nothing more - // to do until it gets a status. This ContainerSource will be reconciled - // again when the Deployment is updated. - return nil - } - return err - } - - // Update Deployment spec if it's changed - expected := resources.MakeDeployment(nil, args) - // Since the Deployment spec has fields defaulted by the webhook, it won't - // be equal to expected. Use DeepDerivative to compare only the fields that - // are set in expected. - if !equality.Semantic.DeepDerivative(expected.Spec, deploy.Spec) { - deploy.Spec = expected.Spec - err := r.client.Update(ctx, deploy) - // if no error, update the status. - if err == nil { - source.Status.MarkDeploying("DeployUpdated", "Updated deployment %s", deploy.Name) - } else { - source.Status.MarkDeploying("DeployNeedsUpdate", "Attempting to update deployment %s", deploy.Name) - r.recorder.Eventf(source, corev1.EventTypeWarning, "DeployNeedsUpdate", "Failed to update deployment %q", deploy.Name) - } - // Return after this update or error and reconcile again - return err - } - - // Update source status - if deploy.Status.ReadyReplicas > 0 { - source.Status.MarkDeployed() - } - - return nil -} - -func (r *reconciler) setSinkURIArg(ctx context.Context, source *v1alpha1.ContainerSource, args *resources.ContainerArguments) error { - if uri, ok := sinkArg(source); ok { - args.SinkInArgs = true - source.Status.MarkSink(uri) - return nil - } - - if source.Spec.Sink == nil { - source.Status.MarkNoSink("Missing", "") - return fmt.Errorf("Sink missing from spec") - } - - uri, err := sinks.GetSinkURI(ctx, r.client, source.Spec.Sink, source.Namespace) - if err != nil { - source.Status.MarkNoSink("NotFound", "") - return err - } - source.Status.MarkSink(uri) - args.Sink = uri - - return nil -} - -func sinkArg(source *v1alpha1.ContainerSource) (string, bool) { - for _, a := range source.Spec.Args { - if strings.HasPrefix(a, "--sink=") { - return strings.Replace(a, "--sink=", "", -1), true - } - } - return "", false -} - -func (r *reconciler) getDeployment(ctx context.Context, source *v1alpha1.ContainerSource) (*appsv1.Deployment, error) { - logger := logging.FromContext(ctx) - - list := &appsv1.DeploymentList{} - err := r.client.List( - ctx, - &client.ListOptions{ - Namespace: source.Namespace, - LabelSelector: labels.Everything(), - // 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: appsv1.SchemeGroupVersion.String(), - Kind: "Deployment", - }, - }, - }, - list) - if err != nil { - logger.Errorf("Unable to list deployments: %v", zap.Error(err)) - return nil, err - } - for _, c := range list.Items { - if metav1.IsControlledBy(&c, source) { - return &c, nil - } - } - return nil, errors.NewNotFound(schema.GroupResource{}, "") -} - -func (r *reconciler) createDeployment(ctx context.Context, source *v1alpha1.ContainerSource, org *appsv1.Deployment, args *resources.ContainerArguments) (*appsv1.Deployment, error) { - deployment := resources.MakeDeployment(org, args) - - if err := controllerutil.SetControllerReference(source, deployment, r.scheme); err != nil { - return nil, err - } - - if err := r.client.Create(ctx, deployment); err != nil { - return nil, err - } - return deployment, nil -} - -func (r *reconciler) InjectClient(c client.Client) error { - r.client = c - return nil -} diff --git a/pkg/reconciler/containersource/containersource_test.go b/pkg/reconciler/containersource/containersource_test.go deleted file mode 100644 index 958db6b3af3..00000000000 --- a/pkg/reconciler/containersource/containersource_test.go +++ /dev/null @@ -1,642 +0,0 @@ -/* -Copyright 2018 The Knative Authors - -Licensed under the Apache License, Veroute.on 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT 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 containersource - -import ( - "context" - "encoding/json" - "errors" - "fmt" - "testing" - - "github.com/google/go-cmp/cmp" - sourcesv1alpha1 "github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1" - controllertesting "github.com/knative/eventing-sources/pkg/controller/testing" - "github.com/knative/eventing-sources/pkg/reconciler/containersource/resources" - duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" - appsv1 "k8s.io/api/apps/v1" - 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/client-go/kubernetes/scheme" - "k8s.io/client-go/tools/record" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -var ( - trueVal = true - targetURI = "http://addressable.sink.svc.cluster.local/" -) - -const ( - image = "github.com/knative/test/image" - containerSourceName = "testcontainersource" - testNS = "testnamespace" - containerSourceUID = "2a2208d1-ce67-11e8-b3a3-42010a8a00af" - deployGeneratedName = "" //sad trombone - - addressableDNS = "addressable.sink.svc.cluster.local" - - addressableName = "testsink" - addressableKind = "Sink" - addressableAPIVersion = "duck.knative.dev/v1alpha1" - - unaddressableName = "testunaddressable" - unaddressableKind = "KResource" - unaddressableAPIVersion = "duck.knative.dev/v1alpha1" - - sinkServiceName = "testsinkservice" - sinkServiceKind = "Service" - sinkServiceAPIVersion = "v1" -) - -func init() { - // Add types to scheme - sourcesv1alpha1.SchemeBuilder.AddToScheme(scheme.Scheme) - duckv1alpha1.AddToScheme(scheme.Scheme) -} - -var testCases = []controllertesting.TestCase{ - { - Name: "non existent key", - Reconciles: &sourcesv1alpha1.ContainerSource{}, - ReconcileKey: "non-existent-test-ns/non-existent-test-key", - WantErr: false, - }, { - Name: "valid containersource, but sink does not exist", - Reconciles: &sourcesv1alpha1.ContainerSource{}, - InitialState: []runtime.Object{ - getContainerSource(), - }, - ReconcileKey: fmt.Sprintf("%s/%s", testNS, containerSourceName), - WantErrMsg: `sinks.duck.knative.dev "testsink" not found`, - }, { - Name: "valid containersource, but sink is not addressable", - Reconciles: &sourcesv1alpha1.ContainerSource{}, - InitialState: []runtime.Object{ - getContainerSourceUnaddressable(), - getAddressableNoStatus(), - }, - ReconcileKey: fmt.Sprintf("%s/%s", testNS, containerSourceName), - Scheme: scheme.Scheme, - WantErrMsg: `sink "testnamespace/testunaddressable" (duck.knative.dev/v1alpha1, Kind=KResource) does not contain address`, - }, { - Name: "valid containersource, sink is addressable", - Reconciles: &sourcesv1alpha1.ContainerSource{}, - InitialState: []runtime.Object{ - getContainerSource(), - getAddressable(), - }, - ReconcileKey: fmt.Sprintf("%s/%s", testNS, containerSourceName), - Scheme: scheme.Scheme, - WantPresent: []runtime.Object{ - func() runtime.Object { - s := getContainerSource() - s.Status.InitializeConditions() - s.Status.MarkDeploying("Deploying", "Created deployment %s", deployGeneratedName) - s.Status.MarkSink(targetURI) - return s - }(), - }, - IgnoreTimes: true, - }, { - Name: "valid containersource, sink is addressable, fields filled in", - Reconciles: &sourcesv1alpha1.ContainerSource{}, - InitialState: []runtime.Object{ - getContainerSourceFilledIn(), - getAddressable(), - }, - ReconcileKey: fmt.Sprintf("%s/%s", testNS, containerSourceName), - Scheme: scheme.Scheme, - WantPresent: []runtime.Object{ - getDeployment(getContainerSourceFilledIn()), - }, - IgnoreTimes: true, - }, { - Name: "valid containersource, sink is Addressable but sink is nil", - Reconciles: &sourcesv1alpha1.ContainerSource{}, - InitialState: []runtime.Object{ - getContainerSource(), - getAddressableNilAddress(), - }, - ReconcileKey: fmt.Sprintf("%s/%s", testNS, containerSourceName), - Scheme: scheme.Scheme, - WantPresent: []runtime.Object{ - func() runtime.Object { - s := getContainerSource() - s.Status.InitializeConditions() - s.Status.MarkNoSink("NotFound", "") - return s - }(), - }, - IgnoreTimes: true, - WantErrMsg: `sink "testnamespace/testsink" (duck.knative.dev/v1alpha1, Kind=Sink) does not contain address`, - }, { - Name: "invalid containersource, sink is nil", - Reconciles: &sourcesv1alpha1.ContainerSource{}, - InitialState: []runtime.Object{ - func() runtime.Object { - s := getContainerSource() - s.Spec.Sink = nil - return s - }(), - }, - ReconcileKey: fmt.Sprintf("%s/%s", testNS, containerSourceName), - Scheme: scheme.Scheme, - WantPresent: []runtime.Object{ - func() runtime.Object { - s := getContainerSource() - s.Spec.Sink = nil - s.Status.InitializeConditions() - s.Status.MarkNoSink("Missing", "") - return s - }(), - }, - IgnoreTimes: true, - WantErrMsg: `Sink missing from spec`, - }, { - Name: "valid containersource, sink is provided", - Reconciles: &sourcesv1alpha1.ContainerSource{}, - InitialState: []runtime.Object{ - func() runtime.Object { - s := getContainerSource() - s.Spec.Sink = nil - s.Spec.Args = append(s.Spec.Args, fmt.Sprintf("--sink=%s", targetURI)) - return s - }(), - }, - ReconcileKey: fmt.Sprintf("%s/%s", testNS, containerSourceName), - Scheme: scheme.Scheme, - WantPresent: []runtime.Object{ - func() runtime.Object { - s := getContainerSource() - s.Spec.Sink = nil - s.Spec.Args = append(s.Spec.Args, fmt.Sprintf("--sink=%s", targetURI)) - s.Status.InitializeConditions() - s.Status.MarkDeploying("Deploying", "Created deployment %s", deployGeneratedName) - s.Status.MarkSink(targetURI) - return s - }(), - }, - IgnoreTimes: true, - }, { - Name: "valid containersource, labels and annotations given", - Reconciles: &sourcesv1alpha1.ContainerSource{}, - InitialState: []runtime.Object{ - func() runtime.Object { - s := getContainerSource() - s.Spec.Sink = nil - s.Spec.Args = append(s.Spec.Args, fmt.Sprintf("--sink=%s", targetURI)) - s.ObjectMeta.Annotations = map[string]string{"annotation": "solid"} - s.ObjectMeta.Labels = map[string]string{"label": "soliderer"} - return s - }(), - }, - ReconcileKey: fmt.Sprintf("%s/%s", testNS, containerSourceName), - Scheme: scheme.Scheme, - WantPresent: []runtime.Object{ - func() runtime.Object { - s := getContainerSource() - s.Spec.Sink = nil - s.Spec.Args = append(s.Spec.Args, fmt.Sprintf("--sink=%s", targetURI)) - s.Status.InitializeConditions() - s.Status.MarkDeploying("Deploying", "Created deployment %s", deployGeneratedName) - s.Status.MarkSink(targetURI) - s.ObjectMeta.Annotations = map[string]string{"annotation": "solid"} - s.ObjectMeta.Labels = map[string]string{"label": "soliderer"} - return s - }(), - }, - IgnoreTimes: true, - }, { - Name: "valid containersource, sink, and deployment", - Reconciles: &sourcesv1alpha1.ContainerSource{}, - InitialState: []runtime.Object{ - func() runtime.Object { - s := getContainerSource() - s.UID = containerSourceUID - return s - }(), - func() runtime.Object { - // TODO(n3wscott): this is very strange, I was not able to get - // the fake client to return the resources.MakeDeployment version - // back in the list call. I might have missed setting some special - // metadata? Converting an unstructured and setting the fields - // I care about did work. - u := &unstructured.Unstructured{ - Object: map[string]interface{}{ - "apiVersion": "apps/v1", - "kind": "Deployment", - "metadata": map[string]interface{}{ - "namespace": testNS, - "name": containerSourceName + "-abc", - }, - }, - } - u.SetOwnerReferences(getOwnerReferences()) - - d := &appsv1.Deployment{} - d.Status.ReadyReplicas = 1 - j, _ := u.MarshalJSON() - json.Unmarshal(j, d) - - d1 := resources.MakeDeployment(nil, &resources.ContainerArguments{ - Name: containerSourceName, - Sink: "http://" + addressableDNS + "/", - Image: image, - }) - d.Spec = d1.Spec - return d - }(), - getAddressable(), - }, - ReconcileKey: fmt.Sprintf("%s/%s", testNS, containerSourceName), - Scheme: scheme.Scheme, - WantPresent: []runtime.Object{ - func() runtime.Object { - s := getContainerSource() - s.UID = containerSourceUID - s.Status.InitializeConditions() - s.Status.MarkDeployed() - s.Status.MarkSink(targetURI) - return s - }(), - }, - IgnoreTimes: true, - }, { - Name: "valid containersource, sink, but deployment needs update", - Reconciles: &sourcesv1alpha1.ContainerSource{}, - InitialState: []runtime.Object{ - func() runtime.Object { - s := getContainerSource() - s.UID = containerSourceUID - return s - }(), - func() runtime.Object { - // TODO(n3wscott): this is very strange, I was not able to get - // the fake client to return the resources.MakeDeployment version - // back in the list call. I might have missed setting some special - // metadata? Converting an unstructured and setting the fields - // I care about did work. - u := &unstructured.Unstructured{ - Object: map[string]interface{}{ - "apiVersion": "apps/v1", - "kind": "Deployment", - "metadata": map[string]interface{}{ - "namespace": testNS, - "name": containerSourceName + "-abc", - }, - }, - } - u.SetOwnerReferences(getOwnerReferences()) - - d := &appsv1.Deployment{} - d.Status.ReadyReplicas = 1 - j, _ := u.MarshalJSON() - json.Unmarshal(j, d) - - d1 := resources.MakeDeployment(nil, &resources.ContainerArguments{ - Name: containerSourceName, - Sink: "http://old-" + addressableDNS + "/", - Image: image, - }) - d.Spec = d1.Spec - return d - }(), - getAddressable(), - }, - ReconcileKey: fmt.Sprintf("%s/%s", testNS, containerSourceName), - Scheme: scheme.Scheme, - WantPresent: []runtime.Object{ - func() runtime.Object { - s := getContainerSource() - s.UID = containerSourceUID - s.Status.InitializeConditions() - s.Status.MarkDeploying("DeployUpdated", "Updated deployment %s", containerSourceName+"-abc") - s.Status.MarkSink(targetURI) - return s - }(), - }, - IgnoreTimes: true, - }, { - Name: "Error for create deployment", - Reconciles: &sourcesv1alpha1.ContainerSource{}, - InitialState: []runtime.Object{ - func() runtime.Object { - s := getContainerSource() - s.UID = containerSourceUID - return s - }(), - getAddressable(), - }, - ReconcileKey: fmt.Sprintf("%s/%s", testNS, containerSourceName), - Scheme: scheme.Scheme, - Mocks: controllertesting.Mocks{ - MockCreates: []controllertesting.MockCreate{ - func(_ client.Client, _ context.Context, _ runtime.Object) (controllertesting.MockHandled, error) { - return controllertesting.Handled, errors.New("force an error into client create") - }, - }, - }, - IgnoreTimes: true, - WantErrMsg: `force an error into client create`, - }, { - Name: "Error for get source, other than not found", - Reconciles: &sourcesv1alpha1.ContainerSource{}, - InitialState: []runtime.Object{ - func() runtime.Object { - s := getContainerSource() - s.UID = containerSourceUID - return s - }(), - getAddressable(), - }, - ReconcileKey: fmt.Sprintf("%s/%s", testNS, containerSourceName), - Scheme: scheme.Scheme, - Mocks: controllertesting.Mocks{ - MockLists: []controllertesting.MockList{ - func(_ client.Client, _ context.Context, _ *client.ListOptions, _ runtime.Object) (controllertesting.MockHandled, error) { - return controllertesting.Handled, errors.New("force an error into client list") - }, - }, - }, - IgnoreTimes: true, - WantErrMsg: `force an error into client list`, - }, - /* TODO: support k8s service { - Name: "valid containersource, sink is a k8s service", - Reconciles: &sourcesv1alpha1.ContainerSource{}, - InitialState: []runtime.Object{ - getContainerSourceSinkService(), - }, - ReconcileKey: fmt.Sprintf("%s/%s", testNS, containerSourceName), - Scheme: scheme.Scheme, - Objects: []runtime.Object{ - // addressable - &unstructured.Unstructured{ - Object: map[string]interface{}{ - "apiVersion": sinkServiceAPIVersion, - "kind": sinkServiceKind, - "metadata": map[string]interface{}{ - "namespace": testNS, - "name": sinkServiceName, - }, - }}, - }, - },*/ -} - -func TestAllCases(t *testing.T) { - recorder := record.NewBroadcaster().NewRecorder(scheme.Scheme, corev1.EventSource{Component: controllerAgentName}) - - for _, tc := range testCases { - c := tc.GetClient() - - r := &reconciler{ - scheme: tc.Scheme, - recorder: recorder, - } - r.InjectClient(c) - t.Run(tc.Name, tc.Runner(t, r, c)) - } -} - -func getContainerSource() *sourcesv1alpha1.ContainerSource { - obj := &sourcesv1alpha1.ContainerSource{ - TypeMeta: containerSourceType(), - ObjectMeta: om(testNS, containerSourceName), - Spec: sourcesv1alpha1.ContainerSourceSpec{ - Image: image, - Args: []string(nil), - Sink: &corev1.ObjectReference{ - Name: addressableName, - Kind: addressableKind, - APIVersion: addressableAPIVersion, - }, - }, - } - // selflink is not filled in when we create the object, so clear it - obj.ObjectMeta.SelfLink = "" - return obj -} - -func getContainerSourceFilledIn() *sourcesv1alpha1.ContainerSource { - obj := getContainerSource() - obj.ObjectMeta.UID = containerSourceUID - obj.Spec.Args = []string{"--foo", "bar"} - obj.Spec.Env = []corev1.EnvVar{{Name: "FOO", Value: "bar"}} - obj.Spec.ServiceAccountName = "foo" - return obj -} - -func getContainerSourceSinkService() *sourcesv1alpha1.ContainerSource { - obj := &sourcesv1alpha1.ContainerSource{ - TypeMeta: containerSourceType(), - ObjectMeta: om(testNS, containerSourceName), - Spec: sourcesv1alpha1.ContainerSourceSpec{ - Image: image, - Args: []string(nil), - Sink: &corev1.ObjectReference{ - Name: sinkServiceName, - Kind: sinkServiceKind, - APIVersion: sinkServiceAPIVersion, - }, - }, - } - // selflink is not filled in when we create the object, so clear it - obj.ObjectMeta.SelfLink = "" - return obj -} - -func getContainerSourceUnaddressable() *sourcesv1alpha1.ContainerSource { - obj := &sourcesv1alpha1.ContainerSource{ - TypeMeta: containerSourceType(), - ObjectMeta: om(testNS, containerSourceName), - Spec: sourcesv1alpha1.ContainerSourceSpec{ - Image: image, - Args: []string{}, - Sink: &corev1.ObjectReference{ - Name: unaddressableName, - Kind: unaddressableKind, - APIVersion: unaddressableAPIVersion, - }, - }, - } - // selflink is not filled in when we create the object, so clear it - obj.ObjectMeta.SelfLink = "" - return obj -} - -func getAddressable() *unstructured.Unstructured { - return &unstructured.Unstructured{ - Object: map[string]interface{}{ - "apiVersion": addressableAPIVersion, - "kind": addressableKind, - "metadata": map[string]interface{}{ - "namespace": testNS, - "name": addressableName, - }, - "status": map[string]interface{}{ - "address": map[string]interface{}{ - "hostname": addressableDNS, - }, - }, - }, - } -} - -func getAddressableNoStatus() *unstructured.Unstructured { - return &unstructured.Unstructured{ - Object: map[string]interface{}{ - "apiVersion": unaddressableAPIVersion, - "kind": unaddressableKind, - "metadata": map[string]interface{}{ - "namespace": testNS, - "name": unaddressableName, - }, - }, - } -} - -func getAddressableNilAddress() *unstructured.Unstructured { - return &unstructured.Unstructured{ - Object: map[string]interface{}{ - "apiVersion": addressableAPIVersion, - "kind": addressableKind, - "metadata": map[string]interface{}{ - "namespace": testNS, - "name": addressableName, - }, - "status": map[string]interface{}{ - "address": map[string]interface{}(nil), - }, - }, - } -} - -func getDeployment(source *sourcesv1alpha1.ContainerSource) *appsv1.Deployment { - addressableURI := fmt.Sprintf("http://%s/", addressableDNS) - args := append(source.Spec.Args, fmt.Sprintf("--sink=%s", addressableURI)) - env := append(source.Spec.Env, corev1.EnvVar{Name: "SINK", Value: addressableURI}) - return &appsv1.Deployment{ - TypeMeta: deploymentType(), - ObjectMeta: metav1.ObjectMeta{ - GenerateName: fmt.Sprintf("%s-", source.Name), - Namespace: source.Namespace, - OwnerReferences: getOwnerReferences(), - }, - Spec: appsv1.DeploymentSpec{ - Selector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - "eventing.knative.dev/source": source.Name, - }, - }, - Template: corev1.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Annotations: map[string]string{ - "sidecar.istio.io/inject": "true", - }, - Labels: map[string]string{ - "eventing.knative.dev/source": source.Name, - }, - }, - Spec: corev1.PodSpec{ - Containers: []corev1.Container{{ - Name: "source", - Image: source.Spec.Image, - Args: args, - Env: env, - ImagePullPolicy: corev1.PullIfNotPresent, - }}, - ServiceAccountName: source.Spec.ServiceAccountName, - }, - }, - }, - } -} - -func containerSourceType() metav1.TypeMeta { - return metav1.TypeMeta{ - APIVersion: sourcesv1alpha1.SchemeGroupVersion.String(), - Kind: "ContainerSource", - } -} - -func deploymentType() metav1.TypeMeta { - return metav1.TypeMeta{ - APIVersion: appsv1.SchemeGroupVersion.String(), - Kind: "Deployment", - } -} - -func om(namespace, name string) metav1.ObjectMeta { - return metav1.ObjectMeta{ - Namespace: namespace, - Name: name, - SelfLink: fmt.Sprintf("/apis/eventing/sources/v1alpha1/namespaces/%s/object/%s", namespace, name), - } -} - -func getOwnerReferences() []metav1.OwnerReference { - return []metav1.OwnerReference{{ - APIVersion: sourcesv1alpha1.SchemeGroupVersion.String(), - Kind: "ContainerSource", - Name: containerSourceName, - Controller: &trueVal, - BlockOwnerDeletion: &trueVal, - UID: containerSourceUID, - }} -} - -// Direct Unit tests. - -func TestObjectNotContainerSource(t *testing.T) { - r := reconciler{} - obj := &corev1.ObjectReference{ - Name: unaddressableName, - Kind: unaddressableKind, - APIVersion: unaddressableAPIVersion, - } - - got := obj.DeepCopy() - gotErr := r.Reconcile(context.TODO(), got) - var want runtime.Object = obj - if diff := cmp.Diff(want, got); diff != "" { - t.Errorf("unexpected returned object (-want, +got) = %v", diff) - } - if gotErr != nil { - t.Errorf("unexpected returned error %v", gotErr) - } -} - -func TestObjectHasDeleteTimestamp(t *testing.T) { - r := reconciler{} - obj := getContainerSource() - - now := metav1.Now() - obj.DeletionTimestamp = &now - got := obj.DeepCopy() - gotErr := r.Reconcile(context.TODO(), got) - var want runtime.Object = obj - if diff := cmp.Diff(want, got); diff != "" { - t.Errorf("unexpected returned object (-want, +got) = %v", diff) - } - if gotErr != nil { - t.Errorf("unexpected returned error %v", gotErr) - } -} diff --git a/pkg/reconciler/containersource/resources/arguments.go b/pkg/reconciler/containersource/resources/arguments.go deleted file mode 100644 index 9eb2884f4f7..00000000000 --- a/pkg/reconciler/containersource/resources/arguments.go +++ /dev/null @@ -1,34 +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 ( - corev1 "k8s.io/api/core/v1" -) - -type ContainerArguments struct { - Name string - Namespace string - Image string - Args []string - Env []corev1.EnvVar - ServiceAccountName string - SinkInArgs bool - Sink string - Annotations map[string]string - Labels map[string]string -} diff --git a/pkg/reconciler/containersource/resources/deployment.go b/pkg/reconciler/containersource/resources/deployment.go deleted file mode 100644 index 2e253dc3531..00000000000 --- a/pkg/reconciler/containersource/resources/deployment.go +++ /dev/null @@ -1,115 +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 ( - "fmt" - "strings" - - appsv1 "k8s.io/api/apps/v1" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -const sourceLabelKey = "eventing.knative.dev/source" - -func MakeDeployment(org *appsv1.Deployment, args *ContainerArguments) *appsv1.Deployment { - - containerArgs := []string(nil) - if args != nil { - containerArgs = args.Args - } - // if sink is already in the provided args.Args, don't attempt to add - if !args.SinkInArgs { - remote := fmt.Sprintf("--sink=%s", args.Sink) - containerArgs = append(containerArgs, remote) - } - - env := append(args.Env, corev1.EnvVar{Name: "SINK", Value: sinkArg(args)}) - - deploy := &appsv1.Deployment{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "apps/v1", - Kind: "Deployment", - }, - ObjectMeta: metav1.ObjectMeta{ - GenerateName: args.Name + "-", - Namespace: args.Namespace, - }, - Spec: appsv1.DeploymentSpec{ - Selector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - sourceLabelKey: args.Name, - }, - }, - Template: corev1.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Annotations: map[string]string{ - "sidecar.istio.io/inject": "true", - }, - Labels: map[string]string{ - sourceLabelKey: args.Name, - }, - }, - Spec: corev1.PodSpec{ - ServiceAccountName: args.ServiceAccountName, - Containers: []corev1.Container{ - { - Name: "source", - Image: args.Image, - Args: containerArgs, - Env: env, - ImagePullPolicy: corev1.PullIfNotPresent, - }, - }, - }, - }, - }, - } - - // Then wire through any annotations from the source. Not a bug by allowing - // the container to override Istio injection. - if args.Annotations != nil { - for k, v := range args.Annotations { - deploy.Spec.Template.ObjectMeta.Annotations[k] = v - } - } - - // Then wire through any labels from the source. Do not allow to override - // our source name. This seems like it would be way errorprone by allowing - // the matchlabels then to not match, or we'd have to force them to match, etc. - // just don't allow it. - if args.Labels != nil { - for k, v := range args.Labels { - if k != sourceLabelKey { - deploy.Spec.Template.ObjectMeta.Labels[k] = v - } - } - } - return deploy -} - -func sinkArg(args *ContainerArguments) string { - if args.SinkInArgs { - for _, a := range args.Args { - if strings.HasPrefix(a, "--sink=") { - return strings.Replace(a, "--sink=", "", -1) - } - } - } - return args.Sink -} diff --git a/pkg/reconciler/containersource/resources/deployment_test.go b/pkg/reconciler/containersource/resources/deployment_test.go deleted file mode 100644 index db01e14a23a..00000000000 --- a/pkg/reconciler/containersource/resources/deployment_test.go +++ /dev/null @@ -1,292 +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 ( - "testing" - - "github.com/google/go-cmp/cmp" - appsv1 "k8s.io/api/apps/v1" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -func TestMakeDeployment_sinkoverrideannotationlabelnotallowed(t *testing.T) { - got := MakeDeployment(nil, &ContainerArguments{ - Name: "test-name", - Namespace: "test-namespace", - Image: "test-image", - Args: []string{"--test1=args1", "--test2=args2"}, - Env: []corev1.EnvVar{{ - Name: "test1", - Value: "arg1", - }, { - Name: "test2", - ValueFrom: &corev1.EnvVarSource{ - SecretKeyRef: &corev1.SecretKeySelector{ - Key: "test2-secret", - }, - }, - }}, - ServiceAccountName: "test-service-account", - SinkInArgs: false, - Sink: "test-sink", - Labels: map[string]string{ - "eventing.knative.dev/source": "not-allowed", - "anotherlabel": "extra-label", - }, - Annotations: map[string]string{ - "sidecar.istio.io/inject": "false", - "anotherannotation": "extra-annotation", - }, - }) - - want := &appsv1.Deployment{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "apps/v1", - Kind: "Deployment", - }, - ObjectMeta: metav1.ObjectMeta{ - GenerateName: "test-name-", - Namespace: "test-namespace", - }, - Spec: appsv1.DeploymentSpec{ - Selector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - "eventing.knative.dev/source": "test-name", - }, - }, - Template: corev1.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Annotations: map[string]string{ - "sidecar.istio.io/inject": "false", - "anotherannotation": "extra-annotation", - }, - Labels: map[string]string{ - "eventing.knative.dev/source": "test-name", - "anotherlabel": "extra-label", - }, - }, - Spec: corev1.PodSpec{ - ServiceAccountName: "test-service-account", - Containers: []corev1.Container{ - { - Name: "source", - Image: "test-image", - Args: []string{ - "--test1=args1", - "--test2=args2", - "--sink=test-sink", - }, - Env: []corev1.EnvVar{ - { - Name: "test1", - Value: "arg1", - }, { - Name: "test2", - ValueFrom: &corev1.EnvVarSource{ - SecretKeyRef: &corev1.SecretKeySelector{ - Key: "test2-secret", - }, - }, - }, { - Name: "SINK", - Value: "test-sink", - }}, - ImagePullPolicy: corev1.PullIfNotPresent, - }, - }, - }, - }, - }, - } - - if diff := cmp.Diff(want, got); diff != "" { - t.Errorf("unexpected deploy (-want, +got) = %v", diff) - } -} - -func TestMakeDeployment_sink(t *testing.T) { - got := MakeDeployment(nil, &ContainerArguments{ - Name: "test-name", - Namespace: "test-namespace", - Image: "test-image", - Args: []string{"--test1=args1", "--test2=args2"}, - Env: []corev1.EnvVar{{ - Name: "test1", - Value: "arg1", - }, { - Name: "test2", - ValueFrom: &corev1.EnvVarSource{ - SecretKeyRef: &corev1.SecretKeySelector{ - Key: "test2-secret", - }, - }, - }}, - ServiceAccountName: "test-service-account", - SinkInArgs: false, - Sink: "test-sink", - }) - - want := &appsv1.Deployment{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "apps/v1", - Kind: "Deployment", - }, - ObjectMeta: metav1.ObjectMeta{ - GenerateName: "test-name-", - Namespace: "test-namespace", - }, - Spec: appsv1.DeploymentSpec{ - Selector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - "eventing.knative.dev/source": "test-name", - }, - }, - Template: corev1.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Annotations: map[string]string{ - "sidecar.istio.io/inject": "true", - }, - Labels: map[string]string{ - "eventing.knative.dev/source": "test-name", - }, - }, - Spec: corev1.PodSpec{ - ServiceAccountName: "test-service-account", - Containers: []corev1.Container{ - { - Name: "source", - Image: "test-image", - Args: []string{ - "--test1=args1", - "--test2=args2", - "--sink=test-sink", - }, - Env: []corev1.EnvVar{ - { - Name: "test1", - Value: "arg1", - }, { - Name: "test2", - ValueFrom: &corev1.EnvVarSource{ - SecretKeyRef: &corev1.SecretKeySelector{ - Key: "test2-secret", - }, - }, - }, { - Name: "SINK", - Value: "test-sink", - }}, - ImagePullPolicy: corev1.PullIfNotPresent, - }, - }, - }, - }, - }, - } - - if diff := cmp.Diff(want, got); diff != "" { - t.Errorf("unexpected deploy (-want, +got) = %v", diff) - } -} - -func TestMakeDeployment_sinkinargs(t *testing.T) { - got := MakeDeployment(nil, &ContainerArguments{ - Name: "test-name", - Namespace: "test-namespace", - Image: "test-image", - Args: []string{"--test1=args1", "--test2=args2", "--sink=test-sink"}, - Env: []corev1.EnvVar{{ - Name: "test1", - Value: "arg1", - }, { - Name: "test2", - ValueFrom: &corev1.EnvVarSource{ - SecretKeyRef: &corev1.SecretKeySelector{ - Key: "test2-secret", - }, - }, - }}, - ServiceAccountName: "test-service-account", - SinkInArgs: true, - Labels: map[string]string{"eventing.knative.dev/source": "test-name"}, - Annotations: map[string]string{"sidecar.istio.io/inject": "true"}, - }) - - want := &appsv1.Deployment{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "apps/v1", - Kind: "Deployment", - }, - ObjectMeta: metav1.ObjectMeta{ - GenerateName: "test-name-", - Namespace: "test-namespace", - }, - Spec: appsv1.DeploymentSpec{ - Selector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - "eventing.knative.dev/source": "test-name", - }, - }, - Template: corev1.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Annotations: map[string]string{ - "sidecar.istio.io/inject": "true", - }, - Labels: map[string]string{ - "eventing.knative.dev/source": "test-name", - }, - }, - Spec: corev1.PodSpec{ - ServiceAccountName: "test-service-account", - Containers: []corev1.Container{ - { - Name: "source", - Image: "test-image", - Args: []string{ - "--test1=args1", - "--test2=args2", - "--sink=test-sink", - }, - Env: []corev1.EnvVar{ - { - Name: "test1", - Value: "arg1", - }, { - Name: "test2", - ValueFrom: &corev1.EnvVarSource{ - SecretKeyRef: &corev1.SecretKeySelector{ - Key: "test2-secret", - }, - }, - }, { - Name: "SINK", - Value: "test-sink", - }}, - ImagePullPolicy: corev1.PullIfNotPresent, - }, - }, - }, - }, - }, - } - - if diff := cmp.Diff(want, got); diff != "" { - t.Errorf("unexpected deploy (-want, +got) = %v", diff) - } -} diff --git a/pkg/reconciler/cronjobsource/cronjobsource.go b/pkg/reconciler/cronjobsource/cronjobsource.go new file mode 100644 index 00000000000..22f3bbb855a --- /dev/null +++ b/pkg/reconciler/cronjobsource/cronjobsource.go @@ -0,0 +1,278 @@ +/* +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 cronjobsource + +import ( + "context" + "fmt" + "os" + "reflect" + "time" + + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/equality" + apierrors "k8s.io/apimachinery/pkg/api/errors" + apierrs "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" + appsv1informers "k8s.io/client-go/informers/apps/v1" + appsv1listers "k8s.io/client-go/listers/apps/v1" + "k8s.io/client-go/tools/cache" + + "github.com/knative/eventing/pkg/apis/sources/v1alpha1" + sourceinformers "github.com/knative/eventing/pkg/client/informers/externalversions/sources/v1alpha1" + listers "github.com/knative/eventing/pkg/client/listers/sources/v1alpha1" + "github.com/knative/eventing/pkg/duck" + "github.com/knative/eventing/pkg/reconciler" + "github.com/knative/eventing/pkg/reconciler/cronjobsource/resources" + "github.com/knative/pkg/controller" + "github.com/knative/pkg/logging" + "github.com/robfig/cron" + "go.uber.org/zap" +) + +const ( + // ReconcilerName is the name of the reconciler + ReconcilerName = "CronJobSources" + // controllerAgentName is the string used by this controller to identify + // itself when creating events. + controllerAgentName = "cronjob-source-controller" + + // Name of the corev1.Events emitted from the reconciliation process + cronjobReconciled = "CronJobSourceReconciled" + cronjobUpdateStatusFailed = "CronJobSourceUpdateStatusFailed" + + // raImageEnvVar is the name of the environment variable that contains the receive adapter's + // image. It must be defined. + raImageEnvVar = "CRONJOB_RA_IMAGE" +) + +type Reconciler struct { + *reconciler.Base + + receiveAdapterImage string + + // listers index properties about resources + cronjobLister listers.CronJobSourceLister + deploymentLister appsv1listers.DeploymentLister +} + +// 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, + cronjobsourceInformer sourceinformers.CronJobSourceInformer, + deploymentInformer appsv1informers.DeploymentInformer, +) *controller.Impl { + raImage, defined := os.LookupEnv(raImageEnvVar) + if !defined { + panic(fmt.Errorf("required environment variable %q not defined", raImageEnvVar)) + } + + r := &Reconciler{ + Base: reconciler.NewBase(opt, controllerAgentName), + receiveAdapterImage: raImage, + cronjobLister: cronjobsourceInformer.Lister(), + deploymentLister: deploymentInformer.Lister(), + } + impl := controller.NewImpl(r, r.Logger, ReconcilerName, reconciler.MustNewStatsReporter(ReconcilerName, r.Logger)) + + r.Logger.Info("Setting up event handlers") + cronjobsourceInformer.Informer().AddEventHandler(reconciler.Handler(impl.Enqueue)) + + deploymentInformer.Informer().AddEventHandler(cache.FilteringResourceEventHandler{ + FilterFunc: controller.Filter(v1alpha1.SchemeGroupVersion.WithKind("CronJobSource")), + Handler: reconciler.Handler(impl.EnqueueControllerOf), + }) + + return impl +} + +// Reconcile compares the actual state with the desired, and attempts to +// converge the two. It then updates the Status block of the CronJobSource +// 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 + } + + // Get the CronJobSource resource with this namespace/name + original, err := r.cronjobLister.CronJobSources(namespace).Get(name) + if apierrs.IsNotFound(err) { + // The resource may no longer exist, in which case we stop processing. + logging.FromContext(ctx).Error("CronJobSource key in work queue no longer exists", zap.Any("key", key)) + return nil + } else if err != nil { + return err + } + + // Don't modify the informers copy + cronjob := original.DeepCopy() + + // Reconcile this copy of the CronJobSource and then write back any status + // updates regardless of whether the reconcile error out. + err = r.reconcile(ctx, cronjob) + if err != nil { + logging.FromContext(ctx).Warn("Error reconciling CronJobSource", zap.Error(err)) + } else { + logging.FromContext(ctx).Debug("CronJobSource reconciled") + r.Recorder.Eventf(cronjob, corev1.EventTypeNormal, cronjobReconciled, "CronJobSource reconciled: %q", cronjob.Name) + } + + if _, updateStatusErr := r.updateStatus(ctx, cronjob.DeepCopy()); updateStatusErr != nil { + logging.FromContext(ctx).Warn("Failed to update the CronJobSource", zap.Error(err)) + r.Recorder.Eventf(cronjob, corev1.EventTypeWarning, cronjobUpdateStatusFailed, "Failed to update CronJobSource's status: %v", err) + return updateStatusErr + } + + // Requeue if the resource is not ready: + return err +} + +func (r *Reconciler) reconcile(ctx context.Context, cronjob *v1alpha1.CronJobSource) error { + // This Source attempts to reconcile three things. + // 1. Determine the sink's URI. + // - Nothing to delete. + // 2. Create a receive adapter in the form of a Deployment. + // - Will be garbage collected by K8s when this CronJobSource is deleted. + + cronjob.Status.InitializeConditions() + + _, err := cron.ParseStandard(cronjob.Spec.Schedule) + if err != nil { + cronjob.Status.MarkInvalidSchedule("Invalid", "") + return err + } + cronjob.Status.MarkSchedule() + sinkURI, err := duck.GetSinkURI(ctx, r.DynamicClientSet, cronjob.Spec.Sink, cronjob.Namespace) + if err != nil { + cronjob.Status.MarkNoSink("NotFound", "") + return err + } + cronjob.Status.MarkSink(sinkURI) + + _, err = r.createReceiveAdapter(ctx, cronjob, sinkURI) + if err != nil { + r.Logger.Error("Unable to create the receive adapter", zap.Error(err)) + return err + } + cronjob.Status.MarkDeployed() + return nil +} + +func (r *Reconciler) createReceiveAdapter(ctx context.Context, src *v1alpha1.CronJobSource, sinkURI string) (*appsv1.Deployment, error) { + ra, err := r.getReceiveAdapter(ctx, src) + if err != nil && !apierrors.IsNotFound(err) { + logging.FromContext(ctx).Error("Unable to get an existing receive adapter", zap.Error(err)) + return nil, err + } + adapterArgs := resources.ReceiveAdapterArgs{ + Image: r.receiveAdapterImage, + Source: src, + Labels: resources.Labels(src.Name), + SinkURI: sinkURI, + } + expected := resources.MakeReceiveAdapter(&adapterArgs) + if ra != nil { + if r.podSpecChanged(ra.Spec.Template.Spec, expected.Spec.Template.Spec) { + ra.Spec.Template.Spec = expected.Spec.Template.Spec + if ra, err = r.KubeClientSet.AppsV1().Deployments(src.Namespace).Update(ra); err != nil { + return ra, err + } + logging.FromContext(ctx).Desugar().Info("Receive Adapter updated.", zap.Any("receiveAdapter", ra)) + } else { + logging.FromContext(ctx).Desugar().Info("Reusing existing receive adapter", zap.Any("receiveAdapter", ra)) + } + return ra, nil + } + + if ra, err = r.KubeClientSet.AppsV1().Deployments(src.Namespace).Create(expected); err != nil { + return nil, err + } + logging.FromContext(ctx).Desugar().Info("Receive Adapter created.", zap.Any("receiveAdapter", expected)) + return ra, err +} + +func (r *Reconciler) podSpecChanged(oldPodSpec corev1.PodSpec, newPodSpec corev1.PodSpec) bool { + if !equality.Semantic.DeepDerivative(newPodSpec, oldPodSpec) { + return true + } + if len(oldPodSpec.Containers) != len(newPodSpec.Containers) { + return true + } + for i := range newPodSpec.Containers { + if !equality.Semantic.DeepEqual(newPodSpec.Containers[i].Env, oldPodSpec.Containers[i].Env) { + return true + } + } + return false +} + +func (r *Reconciler) getReceiveAdapter(ctx context.Context, src *v1alpha1.CronJobSource) (*appsv1.Deployment, error) { + dl, err := r.KubeClientSet.AppsV1().Deployments(src.Namespace).List(metav1.ListOptions{ + LabelSelector: r.getLabelSelector(src).String(), + }) + if err != nil { + logging.FromContext(ctx).Desugar().Error("Unable to list cronjobs: %v", zap.Error(err)) + return nil, err + } + for _, dep := range dl.Items { + if metav1.IsControlledBy(&dep, src) { + return &dep, nil + } + } + return nil, apierrors.NewNotFound(schema.GroupResource{}, "") +} + +func (r *Reconciler) getLabelSelector(src *v1alpha1.CronJobSource) labels.Selector { + return labels.SelectorFromSet(resources.Labels(src.Name)) +} + +func (r *Reconciler) updateStatus(ctx context.Context, desired *v1alpha1.CronJobSource) (*v1alpha1.CronJobSource, error) { + cronjob, err := r.cronjobLister.CronJobSources(desired.Namespace).Get(desired.Name) + if err != nil { + return nil, err + } + + // If there's nothing to update, just return. + if reflect.DeepEqual(cronjob.Status, desired.Status) { + return cronjob, nil + } + + becomesReady := desired.Status.IsReady() && !cronjob.Status.IsReady() + + // Don't modify the informers copy. + existing := cronjob.DeepCopy() + existing.Status = desired.Status + + cj, err := r.EventingClientSet.SourcesV1alpha1().CronJobSources(desired.Namespace).UpdateStatus(existing) + if err == nil && becomesReady { + duration := time.Since(cj.ObjectMeta.CreationTimestamp.Time) + r.Logger.Infof("CronJobSource %q became ready after %v", cronjob.Name, duration) + //r.StatsReporter.ReportServiceReady(subscription.Namespace, subscription.Name, duration) // TODO: stats + } + + return cj, err +} diff --git a/pkg/reconciler/cronjobsource/cronjobsource_test.go b/pkg/reconciler/cronjobsource/cronjobsource_test.go new file mode 100644 index 00000000000..7111970bd84 --- /dev/null +++ b/pkg/reconciler/cronjobsource/cronjobsource_test.go @@ -0,0 +1,325 @@ +/* +Copyright 2019 The Knative Authors + +Licensed under the Apache License, Veroute.on 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT 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 cronjobsource + +import ( + "context" + "errors" + "fmt" + "testing" + + sourcesv1alpha1 "github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1" + controllertesting "github.com/knative/eventing-sources/pkg/controller/testing" + duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" + v1 "k8s.io/api/apps/v1" + 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/client-go/kubernetes/scheme" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +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() + + trueVal = true +) + +const ( + raImage = "test-ra-image" + + image = "github.com/knative/test/image" + sourceName = "test-cronjob-source" + sourceUID = "1234-5678-90" + testNS = "testnamespace" + testSchedule = "*/2 * * * *" + testData = "data" + + addressableName = "testsink" + addressableKind = "Sink" + addressableAPIVersion = "duck.knative.dev/v1alpha1" + addressableDNS = "sinkable.sink.svc.cluster.local" + addressableURI = "http://sinkable.sink.svc.cluster.local/" +) + +func init() { + // Add types to scheme + v1.AddToScheme(scheme.Scheme) + corev1.AddToScheme(scheme.Scheme) + sourcesv1alpha1.SchemeBuilder.AddToScheme(scheme.Scheme) + duckv1alpha1.AddToScheme(scheme.Scheme) +} + +func TestReconcile(t *testing.T) { + testCases := []controllertesting.TestCase{ + { + Name: "not a Cron Job source", + // This is not a CronJobSource. + Reconciles: getNonCronJobSource(), + InitialState: []runtime.Object{ + getNonCronJobSource(), + }, + }, { + Name: "invalid schedule", + InitialState: []runtime.Object{ + getSourceWithInvalidSchedule(), + }, + Reconciles: getSourceWithInvalidSchedule(), + WantErrMsg: "Expected exactly 5 fields, found 2: invalid schedule", + }, { + Name: "cannot get sinkURI", + InitialState: []runtime.Object{ + getSource(), + }, + WantPresent: []runtime.Object{ + getSourceWithoutSink(), + }, + WantErrMsg: "sinks.duck.knative.dev \"testsink\" not found", + }, { + Name: "cannot create receive adapter", + InitialState: []runtime.Object{ + getSource(), + getAddressable(), + }, + Mocks: controllertesting.Mocks{ + MockCreates: []controllertesting.MockCreate{ + func(_ client.Client, _ context.Context, _ runtime.Object) (controllertesting.MockHandled, error) { + return controllertesting.Handled, errors.New("test-induced-error") + }, + }, + }, + WantPresent: []runtime.Object{ + getSourceWithSink(), + }, + WantErrMsg: "test-induced-error", + }, { + Name: "cannot list deployments", + InitialState: []runtime.Object{ + getSource(), + getAddressable(), + }, + Mocks: controllertesting.Mocks{ + MockLists: []controllertesting.MockList{ + func(_ client.Client, _ context.Context, _ *client.ListOptions, _ runtime.Object) (controllertesting.MockHandled, error) { + return controllertesting.Handled, errors.New("test-induced-error") + }, + }, + }, + WantPresent: []runtime.Object{ + getSourceWithSink(), + }, + WantErrMsg: "test-induced-error", + }, { + Name: "successful create", + InitialState: []runtime.Object{ + getSource(), + getAddressable(), + }, + WantPresent: []runtime.Object{ + getReadySource(), + }, + }, { + Name: "successful create - reuse existing receive adapter", + InitialState: []runtime.Object{ + getSource(), + getAddressable(), + getReceiveAdapter(), + }, + Mocks: controllertesting.Mocks{ + MockCreates: []controllertesting.MockCreate{ + func(_ client.Client, _ context.Context, _ runtime.Object) (controllertesting.MockHandled, error) { + return controllertesting.Handled, errors.New("an error that won't be seen because create is not called") + }, + }, + }, + WantPresent: []runtime.Object{ + getReadySource(), + }, + }, + } + for _, tc := range testCases { + tc.IgnoreTimes = true + tc.ReconcileKey = fmt.Sprintf("%s/%s", testNS, sourceName) + if tc.Reconciles == nil { + tc.Reconciles = getSource() + } + tc.Scheme = scheme.Scheme + + c := tc.GetClient() + r := &reconciler{ + client: c, + scheme: tc.Scheme, + + receiveAdapterImage: raImage, + } + r.InjectClient(c) + t.Run(tc.Name, tc.Runner(t, r, c)) + } +} + +func getNonCronJobSource() *sourcesv1alpha1.ContainerSource { + obj := &sourcesv1alpha1.ContainerSource{ + TypeMeta: metav1.TypeMeta{ + APIVersion: sourcesv1alpha1.SchemeGroupVersion.String(), + Kind: "ContainerSource", + }, + ObjectMeta: om(testNS, sourceName), + Spec: sourcesv1alpha1.ContainerSourceSpec{ + Image: image, + Args: []string(nil), + Sink: &corev1.ObjectReference{ + Name: addressableName, + Kind: addressableKind, + APIVersion: addressableAPIVersion, + }, + }, + } + // selflink is not filled in when we create the object, so clear it + obj.ObjectMeta.SelfLink = "" + return obj +} + +func getSource() *sourcesv1alpha1.CronJobSource { + obj := &sourcesv1alpha1.CronJobSource{ + TypeMeta: metav1.TypeMeta{ + APIVersion: sourcesv1alpha1.SchemeGroupVersion.String(), + Kind: "CronJobSource", + }, + ObjectMeta: om(testNS, sourceName), + Spec: sourcesv1alpha1.CronJobSourceSpec{ + Schedule: testSchedule, + Data: testData, + Sink: &corev1.ObjectReference{ + Name: addressableName, + Kind: addressableKind, + APIVersion: addressableAPIVersion, + }, + }, + } + // selflink is not filled in when we create the object, so clear it + obj.ObjectMeta.SelfLink = "" + return obj +} + +func getDeletingSource() *sourcesv1alpha1.CronJobSource { + src := getSource() + src.DeletionTimestamp = &deletionTime + return src +} + +func getSourceWithInvalidSchedule() *sourcesv1alpha1.CronJobSource { + src := getSource() + src.Spec.Schedule = "invalid schedule" + return src +} + +func getSourceWithoutSink() *sourcesv1alpha1.CronJobSource { + src := getSource() + src.Status.InitializeConditions() + src.Status.MarkSchedule() + src.Status.MarkNoSink("NotFound", "") + return src +} + +func getSourceWithSink() *sourcesv1alpha1.CronJobSource { + src := getSource() + src.Status.InitializeConditions() + src.Status.MarkSchedule() + src.Status.MarkSink(addressableURI) + return src +} + +func getReadySource() *sourcesv1alpha1.CronJobSource { + src := getSourceWithSink() + src.Status.MarkDeployed() + return src +} + +func om(namespace, name string) metav1.ObjectMeta { + return metav1.ObjectMeta{ + Namespace: namespace, + Name: name, + SelfLink: fmt.Sprintf("/apis/eventing/sources/v1alpha1/namespaces/%s/object/%s", namespace, name), + UID: sourceUID, + } +} + +func getAddressable() *unstructured.Unstructured { + return &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": addressableAPIVersion, + "kind": addressableKind, + "metadata": map[string]interface{}{ + "namespace": testNS, + "name": addressableName, + }, + "status": map[string]interface{}{ + "address": map[string]interface{}{ + "hostname": addressableDNS, + }, + }, + }, + } +} + +func getReceiveAdapter() *v1.Deployment { + return &v1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + OwnerReferences: []metav1.OwnerReference{ + { + Controller: &trueVal, + UID: sourceUID, + }, + }, + Labels: getLabels(getSource()), + Namespace: testNS, + }, + TypeMeta: metav1.TypeMeta{ + APIVersion: corev1.SchemeGroupVersion.String(), + Kind: "Deployment", + }, + Spec: v1.DeploymentSpec{ + Template: corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + { + Name: "receive-adapter", + Image: raImage, + Env: []corev1.EnvVar{ + { + Name: "SCHEDULE", + Value: testSchedule, + }, + { + Name: "DATA", + Value: testData, + }, + { + Name: "SINK_URI", + Value: addressableURI, + }, + }, + }, + }, + }, + }, + }, + } +} diff --git a/pkg/reconciler/containersource/doc.go b/pkg/reconciler/cronjobsource/doc.go similarity index 80% rename from pkg/reconciler/containersource/doc.go rename to pkg/reconciler/cronjobsource/doc.go index d83e1353fc0..aa960fc7bad 100644 --- a/pkg/reconciler/containersource/doc.go +++ b/pkg/reconciler/cronjobsource/doc.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. @@ -14,5 +14,5 @@ See the License for the specific language governing permissions and limitations under the License. */ -// Package containersource implements the ContainerSource controller. -package containersource +// Package cronjobsource implements the CronJobSource controller. +package cronjobsource diff --git a/vendor/github.com/knative/eventing-sources/pkg/reconciler/containersource/resources/arguments.go b/pkg/reconciler/cronjobsource/resources/labels.go similarity index 57% rename from vendor/github.com/knative/eventing-sources/pkg/reconciler/containersource/resources/arguments.go rename to pkg/reconciler/cronjobsource/resources/labels.go index 9eb2884f4f7..04dc6098fda 100644 --- a/vendor/github.com/knative/eventing-sources/pkg/reconciler/containersource/resources/arguments.go +++ b/pkg/reconciler/cronjobsource/resources/labels.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. @@ -16,19 +16,15 @@ limitations under the License. package resources -import ( - corev1 "k8s.io/api/core/v1" +const ( + // controllerAgentName is the string used by this controller to identify + // itself when creating events. + controllerAgentName = "cronjob-source-controller" ) -type ContainerArguments struct { - Name string - Namespace string - Image string - Args []string - Env []corev1.EnvVar - ServiceAccountName string - SinkInArgs bool - Sink string - Annotations map[string]string - Labels map[string]string +func Labels(name string) map[string]string { + return map[string]string{ + "knative-eventing-source": controllerAgentName, + "knative-eventing-source-name": name, + } } diff --git a/pkg/reconciler/cronjobsource/resources/receive_adapter.go b/pkg/reconciler/cronjobsource/resources/receive_adapter.go new file mode 100644 index 00000000000..9f516db0cab --- /dev/null +++ b/pkg/reconciler/cronjobsource/resources/receive_adapter.go @@ -0,0 +1,90 @@ +/* +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 resources + +import ( + "fmt" + "github.com/knative/pkg/kmeta" + + v1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/knative/eventing/pkg/apis/sources/v1alpha1" +) + +// ReceiveAdapterArgs are the arguments needed to create a Cron Job Source Receive Adapter. Every +// field is required. +type ReceiveAdapterArgs struct { + Image string + Source *v1alpha1.CronJobSource + Labels map[string]string + SinkURI string +} + +// MakeReceiveAdapter generates (but does not insert into K8s) the Receive Adapter Deployment for +// Cron Job Sources. +func MakeReceiveAdapter(args *ReceiveAdapterArgs) *v1.Deployment { + replicas := int32(1) + return &v1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: args.Source.Namespace, + GenerateName: fmt.Sprintf("cronjob-%s-", args.Source.Name), + Labels: args.Labels, + OwnerReferences: []metav1.OwnerReference{ + *kmeta.NewControllerRef(args.Source), + }, + }, + Spec: v1.DeploymentSpec{ + Selector: &metav1.LabelSelector{ + MatchLabels: args.Labels, + }, + Replicas: &replicas, + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + "sidecar.istio.io/inject": "true", // TODO this might be removed. + }, + Labels: args.Labels, + }, + Spec: corev1.PodSpec{ + ServiceAccountName: args.Source.Spec.ServiceAccountName, + Containers: []corev1.Container{ + { + Name: "receive-adapter", + Image: args.Image, + Env: []corev1.EnvVar{ + { + Name: "SCHEDULE", + Value: args.Source.Spec.Schedule, + }, + { + Name: "DATA", + Value: args.Source.Spec.Data, + }, + { + Name: "SINK_URI", + Value: args.SinkURI, + }, + }, + }, + }, + }, + }, + }, + } +} diff --git a/pkg/reconciler/cronjobsource/resources/receive_adapter_test.go b/pkg/reconciler/cronjobsource/resources/receive_adapter_test.go new file mode 100644 index 00000000000..6bf75683b95 --- /dev/null +++ b/pkg/reconciler/cronjobsource/resources/receive_adapter_test.go @@ -0,0 +1,111 @@ +/* +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 resources + +import ( + "testing" + + v1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/google/go-cmp/cmp" + "github.com/knative/eventing/pkg/apis/sources/v1alpha1" +) + +func TestMakeReceiveAdapter(t *testing.T) { + src := &v1alpha1.CronJobSource{ + ObjectMeta: metav1.ObjectMeta{ + Name: "source-name", + Namespace: "source-namespace", + }, + Spec: v1alpha1.CronJobSourceSpec{ + ServiceAccountName: "source-svc-acct", + Schedule: "*/2 * * * *", + Data: "data", + }, + } + + got := MakeReceiveAdapter(&ReceiveAdapterArgs{ + Image: "test-image", + Source: src, + Labels: map[string]string{ + "test-key1": "test-value1", + "test-key2": "test-value2", + }, + SinkURI: "sink-uri", + }) + + one := int32(1) + want := &v1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "source-namespace", + GenerateName: "cronjob-source-name-", + Labels: map[string]string{ + "test-key1": "test-value1", + "test-key2": "test-value2", + }, + }, + Spec: v1.DeploymentSpec{ + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "test-key1": "test-value1", + "test-key2": "test-value2", + }, + }, + Replicas: &one, + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + "sidecar.istio.io/inject": "true", + }, + Labels: map[string]string{ + "test-key1": "test-value1", + "test-key2": "test-value2", + }, + }, + Spec: corev1.PodSpec{ + ServiceAccountName: "source-svc-acct", + Containers: []corev1.Container{ + { + Name: "receive-adapter", + Image: "test-image", + Env: []corev1.EnvVar{ + { + Name: "SCHEDULE", + Value: "*/2 * * * *", + }, + { + Name: "DATA", + Value: "data", + }, + { + Name: "SINK_URI", + Value: "sink-uri", + }, + }, + }, + }, + }, + }, + }, + } + + if diff := cmp.Diff(want, got); diff != "" { + t.Errorf("unexpected cron job (-want, +got) = %v", diff) + } +} diff --git a/pkg/reconciler/subscription/subscription.go b/pkg/reconciler/subscription/subscription.go index e241a1b0a70..9c0e9058469 100644 --- a/pkg/reconciler/subscription/subscription.go +++ b/pkg/reconciler/subscription/subscription.go @@ -20,17 +20,16 @@ import ( "context" "encoding/json" "fmt" - "k8s.io/apimachinery/pkg/labels" "reflect" "time" - eventingduck "github.com/knative/eventing/pkg/apis/duck/v1alpha1" + eventingduckv1alpha1 "github.com/knative/eventing/pkg/apis/duck/v1alpha1" "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" + eventingduck "github.com/knative/eventing/pkg/duck" "github.com/knative/eventing/pkg/logging" "github.com/knative/eventing/pkg/reconciler" - "github.com/knative/eventing/pkg/utils/resolve" "github.com/knative/pkg/apis/duck" duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" "github.com/knative/pkg/controller" @@ -40,6 +39,7 @@ import ( "k8s.io/apimachinery/pkg/api/errors" apierrs "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/client-go/tools/cache" @@ -157,7 +157,7 @@ func (r *Reconciler) reconcile(ctx context.Context, subscription *v1alpha1.Subsc } // Verify that `channel` exists. - if _, err := resolve.ObjectReference(ctx, r.DynamicClientSet, subscription.Namespace, &subscription.Spec.Channel); err != nil { + if _, err := eventingduck.ObjectReference(ctx, r.DynamicClientSet, subscription.Namespace, &subscription.Spec.Channel); err != nil { logging.FromContext(ctx).Warn("Failed to validate Channel exists", zap.Error(err), zap.Any("channel", subscription.Spec.Channel)) @@ -165,7 +165,7 @@ func (r *Reconciler) reconcile(ctx context.Context, subscription *v1alpha1.Subsc return err } - subscriberURI, err := resolve.SubscriberSpec(ctx, r.DynamicClientSet, subscription.Namespace, subscription.Spec.Subscriber) + subscriberURI, err := eventingduck.SubscriberSpec(ctx, r.DynamicClientSet, subscription.Namespace, subscription.Spec.Subscriber) if err != nil { logging.FromContext(ctx).Warn("Failed to resolve Subscriber", zap.Error(err), @@ -266,7 +266,7 @@ func (r *Reconciler) resolveResult(ctx context.Context, namespace string, replyS if isNilOrEmptyReply(replyStrategy) { return "", nil } - obj, err := resolve.ObjectReference(ctx, r.DynamicClientSet, namespace, replyStrategy.Channel) + obj, err := eventingduck.ObjectReference(ctx, r.DynamicClientSet, namespace, replyStrategy.Channel) if err != nil { logging.FromContext(ctx).Warn("Failed to fetch ReplyStrategy Channel", zap.Error(err), @@ -280,7 +280,7 @@ func (r *Reconciler) resolveResult(ctx context.Context, namespace string, replyS return "", err } if s.Status.Address != nil { - return resolve.DomainToURL(s.Status.Address.Hostname), nil + return eventingduck.DomainToURL(s.Status.Address.Hostname), nil } return "", fmt.Errorf("status does not contain address") } @@ -331,11 +331,11 @@ func (r *Reconciler) listAllSubscriptionsWithPhysicalChannel(ctx context.Context return subs, nil } -func (r *Reconciler) createSubscribable(subs []v1alpha1.Subscription) *eventingduck.Subscribable { - rv := &eventingduck.Subscribable{} +func (r *Reconciler) createSubscribable(subs []v1alpha1.Subscription) *eventingduckv1alpha1.Subscribable { + rv := &eventingduckv1alpha1.Subscribable{} for _, sub := range subs { if sub.Status.PhysicalSubscription.SubscriberURI != "" || sub.Status.PhysicalSubscription.ReplyURI != "" { - rv.Subscribers = append(rv.Subscribers, eventingduck.ChannelSubscriberSpec{ + rv.Subscribers = append(rv.Subscribers, eventingduckv1alpha1.ChannelSubscriberSpec{ DeprecatedRef: &corev1.ObjectReference{ APIVersion: sub.APIVersion, Kind: sub.Kind, @@ -352,13 +352,13 @@ func (r *Reconciler) createSubscribable(subs []v1alpha1.Subscription) *eventingd return rv } -func (r *Reconciler) patchPhysicalFrom(ctx context.Context, namespace string, physicalFrom corev1.ObjectReference, subs *eventingduck.Subscribable) error { +func (r *Reconciler) patchPhysicalFrom(ctx context.Context, namespace string, physicalFrom corev1.ObjectReference, subs *eventingduckv1alpha1.Subscribable) error { // First get the original object and convert it to only the bits we care about - s, err := resolve.ObjectReference(ctx, r.DynamicClientSet, namespace, &physicalFrom) + s, err := eventingduck.ObjectReference(ctx, r.DynamicClientSet, namespace, &physicalFrom) if err != nil { return err } - original := eventingduck.Channel{} + original := eventingduckv1alpha1.Channel{} err = duck.FromUnstructured(s, &original) if err != nil { return err @@ -372,7 +372,7 @@ func (r *Reconciler) patchPhysicalFrom(ctx context.Context, namespace string, ph return err } - resourceClient, err := resolve.ResourceInterface(r.DynamicClientSet, namespace, &physicalFrom) + resourceClient, err := eventingduck.ResourceInterface(r.DynamicClientSet, namespace, &physicalFrom) if err != nil { logging.FromContext(ctx).Warn("Failed to create dynamic resource client", zap.Error(err)) return err diff --git a/pkg/reconciler/v1alpha1/trigger/trigger.go b/pkg/reconciler/v1alpha1/trigger/trigger.go index 24cc38bb9b3..4a31a602b82 100644 --- a/pkg/reconciler/v1alpha1/trigger/trigger.go +++ b/pkg/reconciler/v1alpha1/trigger/trigger.go @@ -18,6 +18,7 @@ package trigger import ( "context" + "github.com/knative/eventing/pkg/duck" "net/url" "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" @@ -27,7 +28,6 @@ import ( brokerresources "github.com/knative/eventing/pkg/reconciler/v1alpha1/broker/resources" "github.com/knative/eventing/pkg/reconciler/v1alpha1/trigger/path" "github.com/knative/eventing/pkg/reconciler/v1alpha1/trigger/resources" - "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" @@ -251,7 +251,7 @@ func (r *reconciler) reconcile(ctx context.Context, t *v1alpha1.Trigger) error { return err } - subscriberURI, err := resolve.SubscriberSpec(ctx, r.dynamicClient, t.Namespace, t.Spec.Subscriber) + subscriberURI, err := duck.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/third_party/VENDOR-LICENSE b/third_party/VENDOR-LICENSE index 8b36c02a3be..f882c9664f1 100644 --- a/third_party/VENDOR-LICENSE +++ b/third_party/VENDOR-LICENSE @@ -3454,6 +3454,213 @@ SOFTWARE. +=========================================================== +Import: github.com/knative/eventing/vendor/github.com/knative/eventing-sources + + 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 @@ -5898,6 +6105,33 @@ official policies, either expressed or implied, of Richard Crowley. +=========================================================== +Import: github.com/knative/eventing/vendor/github.com/robfig/cron + +Copyright (C) 2012 Rob Figueiredo +All Rights Reserved. + +MIT LICENSE + +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/spf13/pflag diff --git a/vendor/github.com/knative/eventing-sources/pkg/reconciler/containersource/resources/deployment.go b/vendor/github.com/knative/eventing-sources/pkg/reconciler/containersource/resources/deployment.go deleted file mode 100644 index 2e253dc3531..00000000000 --- a/vendor/github.com/knative/eventing-sources/pkg/reconciler/containersource/resources/deployment.go +++ /dev/null @@ -1,115 +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 ( - "fmt" - "strings" - - appsv1 "k8s.io/api/apps/v1" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -const sourceLabelKey = "eventing.knative.dev/source" - -func MakeDeployment(org *appsv1.Deployment, args *ContainerArguments) *appsv1.Deployment { - - containerArgs := []string(nil) - if args != nil { - containerArgs = args.Args - } - // if sink is already in the provided args.Args, don't attempt to add - if !args.SinkInArgs { - remote := fmt.Sprintf("--sink=%s", args.Sink) - containerArgs = append(containerArgs, remote) - } - - env := append(args.Env, corev1.EnvVar{Name: "SINK", Value: sinkArg(args)}) - - deploy := &appsv1.Deployment{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "apps/v1", - Kind: "Deployment", - }, - ObjectMeta: metav1.ObjectMeta{ - GenerateName: args.Name + "-", - Namespace: args.Namespace, - }, - Spec: appsv1.DeploymentSpec{ - Selector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - sourceLabelKey: args.Name, - }, - }, - Template: corev1.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Annotations: map[string]string{ - "sidecar.istio.io/inject": "true", - }, - Labels: map[string]string{ - sourceLabelKey: args.Name, - }, - }, - Spec: corev1.PodSpec{ - ServiceAccountName: args.ServiceAccountName, - Containers: []corev1.Container{ - { - Name: "source", - Image: args.Image, - Args: containerArgs, - Env: env, - ImagePullPolicy: corev1.PullIfNotPresent, - }, - }, - }, - }, - }, - } - - // Then wire through any annotations from the source. Not a bug by allowing - // the container to override Istio injection. - if args.Annotations != nil { - for k, v := range args.Annotations { - deploy.Spec.Template.ObjectMeta.Annotations[k] = v - } - } - - // Then wire through any labels from the source. Do not allow to override - // our source name. This seems like it would be way errorprone by allowing - // the matchlabels then to not match, or we'd have to force them to match, etc. - // just don't allow it. - if args.Labels != nil { - for k, v := range args.Labels { - if k != sourceLabelKey { - deploy.Spec.Template.ObjectMeta.Labels[k] = v - } - } - } - return deploy -} - -func sinkArg(args *ContainerArguments) string { - if args.SinkInArgs { - for _, a := range args.Args { - if strings.HasPrefix(a, "--sink=") { - return strings.Replace(a, "--sink=", "", -1) - } - } - } - return args.Sink -} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/controller/controllerutil/controllerutil.go b/vendor/sigs.k8s.io/controller-runtime/pkg/controller/controllerutil/controllerutil.go deleted file mode 100644 index d918eeaa42e..00000000000 --- a/vendor/sigs.k8s.io/controller-runtime/pkg/controller/controllerutil/controllerutil.go +++ /dev/null @@ -1,178 +0,0 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT 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 controllerutil - -import ( - "context" - "fmt" - "reflect" - - "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/client/apiutil" -) - -// AlreadyOwnedError is an error returned if the object you are trying to assign -// a controller reference is already owned by another controller Object is the -// subject and Owner is the reference for the current owner -type AlreadyOwnedError struct { - Object v1.Object - Owner v1.OwnerReference -} - -func (e *AlreadyOwnedError) Error() string { - return fmt.Sprintf("Object %s/%s is already owned by another %s controller %s", e.Object.GetNamespace(), e.Object.GetName(), e.Owner.Kind, e.Owner.Name) -} - -func newAlreadyOwnedError(Object v1.Object, Owner v1.OwnerReference) *AlreadyOwnedError { - return &AlreadyOwnedError{ - Object: Object, - Owner: Owner, - } -} - -// SetControllerReference sets owner as a Controller OwnerReference on owned. -// This is used for garbage collection of the owned object and for -// reconciling the owner object on changes to owned (with a Watch + EnqueueRequestForOwner). -// Since only one OwnerReference can be a controller, it returns an error if -// there is another OwnerReference with Controller flag set. -func SetControllerReference(owner, object v1.Object, scheme *runtime.Scheme) error { - ro, ok := owner.(runtime.Object) - if !ok { - return fmt.Errorf("is not a %T a runtime.Object, cannot call SetControllerReference", owner) - } - - gvk, err := apiutil.GVKForObject(ro, scheme) - if err != nil { - return err - } - - // Create a new ref - ref := *v1.NewControllerRef(owner, schema.GroupVersionKind{Group: gvk.Group, Version: gvk.Version, Kind: gvk.Kind}) - - existingRefs := object.GetOwnerReferences() - fi := -1 - for i, r := range existingRefs { - if referSameObject(ref, r) { - fi = i - } else if r.Controller != nil && *r.Controller { - return newAlreadyOwnedError(object, r) - } - } - if fi == -1 { - existingRefs = append(existingRefs, ref) - } else { - existingRefs[fi] = ref - } - - // Update owner references - object.SetOwnerReferences(existingRefs) - return nil -} - -// Returns true if a and b point to the same object -func referSameObject(a, b v1.OwnerReference) bool { - aGV, err := schema.ParseGroupVersion(a.APIVersion) - if err != nil { - return false - } - - bGV, err := schema.ParseGroupVersion(b.APIVersion) - if err != nil { - return false - } - - return aGV == bGV && a.Kind == b.Kind && a.Name == b.Name -} - -// OperationResult is the action result of a CreateOrUpdate call -type OperationResult string - -const ( // They should complete the sentence "Deployment default/foo has been ..." - // OperationResultNone means that the resource has not been changed - OperationResultNone OperationResult = "unchanged" - // OperationResultCreated means that a new resource is created - OperationResultCreated OperationResult = "created" - // OperationResultUpdated means that an existing resource is updated - OperationResultUpdated OperationResult = "updated" -) - -// CreateOrUpdate creates or updates the given object obj in the Kubernetes -// cluster. The object's desired state should be reconciled with the existing -// state using the passed in ReconcileFn. obj must be a struct pointer so that -// obj can be updated with the content returned by the Server. -// -// It returns the executed operation and an error. -func CreateOrUpdate(ctx context.Context, c client.Client, obj runtime.Object, f MutateFn) (OperationResult, error) { - // op is the operation we are going to attempt - op := OperationResultNone - - // get the existing object meta - metaObj, ok := obj.(v1.Object) - if !ok { - return OperationResultNone, fmt.Errorf("%T does not implement metav1.Object interface", obj) - } - - // retrieve the existing object - key := client.ObjectKey{ - Name: metaObj.GetName(), - Namespace: metaObj.GetNamespace(), - } - err := c.Get(ctx, key, obj) - - // reconcile the existing object - existing := obj.DeepCopyObject() - existingObjMeta := existing.(v1.Object) - existingObjMeta.SetName(metaObj.GetName()) - existingObjMeta.SetNamespace(metaObj.GetNamespace()) - - if e := f(obj); e != nil { - return OperationResultNone, e - } - - if metaObj.GetName() != existingObjMeta.GetName() { - return OperationResultNone, fmt.Errorf("ReconcileFn cannot mutate objects name") - } - - if metaObj.GetNamespace() != existingObjMeta.GetNamespace() { - return OperationResultNone, fmt.Errorf("ReconcileFn cannot mutate objects namespace") - } - - if errors.IsNotFound(err) { - err = c.Create(ctx, obj) - op = OperationResultCreated - } else if err == nil { - if reflect.DeepEqual(existing, obj) { - return OperationResultNone, nil - } - err = c.Update(ctx, obj) - op = OperationResultUpdated - } else { - return OperationResultNone, err - } - - if err != nil { - op = OperationResultNone - } - return op, err -} - -// MutateFn is a function which mutates the existing object into it's desired state. -type MutateFn func(existing runtime.Object) error diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/controller/controllerutil/doc.go b/vendor/sigs.k8s.io/controller-runtime/pkg/controller/controllerutil/doc.go deleted file mode 100644 index ab386b29cdb..00000000000 --- a/vendor/sigs.k8s.io/controller-runtime/pkg/controller/controllerutil/doc.go +++ /dev/null @@ -1,20 +0,0 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT 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 controllerutil contains utility functions for working with and implementing Controllers. -*/ -package controllerutil From e7eaeea60bfef03d55196b62d5bbb3644b0cd144 Mon Sep 17 00:00:00 2001 From: Scott Nichols Date: Tue, 23 Apr 2019 14:36:13 -0700 Subject: [PATCH 05/25] stash. --- .../cronjobsource/cronjobsource_test.go | 194 ++++++++---------- pkg/reconciler/testing/listers.go | 6 + 2 files changed, 90 insertions(+), 110 deletions(-) diff --git a/pkg/reconciler/cronjobsource/cronjobsource_test.go b/pkg/reconciler/cronjobsource/cronjobsource_test.go index 7111970bd84..2cefb5f393e 100644 --- a/pkg/reconciler/cronjobsource/cronjobsource_test.go +++ b/pkg/reconciler/cronjobsource/cronjobsource_test.go @@ -17,21 +17,32 @@ limitations under the License. package cronjobsource import ( - "context" - "errors" + //"context" + //"errors" "fmt" + "github.com/knative/eventing/pkg/reconciler/cronjobsource/resources" + "os" "testing" - sourcesv1alpha1 "github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1" - controllertesting "github.com/knative/eventing-sources/pkg/controller/testing" + fakeclientset "github.com/knative/eventing/pkg/client/clientset/versioned/fake" + informers "github.com/knative/eventing/pkg/client/informers/externalversions" + "github.com/knative/eventing/pkg/reconciler" duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" - v1 "k8s.io/api/apps/v1" + "github.com/knative/pkg/controller" + logtesting "github.com/knative/pkg/logging/testing" 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/runtime" + kubeinformers "k8s.io/client-go/informers" + fakekubeclientset "k8s.io/client-go/kubernetes/fake" "k8s.io/client-go/kubernetes/scheme" - "sigs.k8s.io/controller-runtime/pkg/client" + + . "github.com/knative/eventing/pkg/reconciler/testing" + . "github.com/knative/pkg/reconciler/testing" + + sourcesv1alpha1 "github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1" + v1 "k8s.io/api/apps/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" ) var ( @@ -61,119 +72,82 @@ const ( func init() { // Add types to scheme - v1.AddToScheme(scheme.Scheme) - corev1.AddToScheme(scheme.Scheme) - sourcesv1alpha1.SchemeBuilder.AddToScheme(scheme.Scheme) - duckv1alpha1.AddToScheme(scheme.Scheme) + _ = v1.AddToScheme(scheme.Scheme) + _ = corev1.AddToScheme(scheme.Scheme) + _ = duckv1alpha1.AddToScheme(scheme.Scheme) + + _ = os.Setenv("CRONJOB_RA_IMAGE", "no-op") } -func TestReconcile(t *testing.T) { - testCases := []controllertesting.TestCase{ +func TestAllCases(t *testing.T) { + table := TableTest{ { - Name: "not a Cron Job source", - // This is not a CronJobSource. - Reconciles: getNonCronJobSource(), - InitialState: []runtime.Object{ - getNonCronJobSource(), - }, - }, { - Name: "invalid schedule", - InitialState: []runtime.Object{ - getSourceWithInvalidSchedule(), - }, - Reconciles: getSourceWithInvalidSchedule(), - WantErrMsg: "Expected exactly 5 fields, found 2: invalid schedule", - }, { - Name: "cannot get sinkURI", - InitialState: []runtime.Object{ - getSource(), - }, - WantPresent: []runtime.Object{ - getSourceWithoutSink(), - }, - WantErrMsg: "sinks.duck.knative.dev \"testsink\" not found", - }, { - Name: "cannot create receive adapter", - InitialState: []runtime.Object{ - getSource(), - getAddressable(), - }, - Mocks: controllertesting.Mocks{ - MockCreates: []controllertesting.MockCreate{ - func(_ client.Client, _ context.Context, _ runtime.Object) (controllertesting.MockHandled, error) { - return controllertesting.Handled, errors.New("test-induced-error") - }, - }, - }, - WantPresent: []runtime.Object{ - getSourceWithSink(), - }, - WantErrMsg: "test-induced-error", + Name: "bad workqueue key", + // Make sure Reconcile handles bad keys. + Key: "too/many/parts", }, { - Name: "cannot list deployments", - InitialState: []runtime.Object{ - getSource(), - getAddressable(), - }, - Mocks: controllertesting.Mocks{ - MockLists: []controllertesting.MockList{ - func(_ client.Client, _ context.Context, _ *client.ListOptions, _ runtime.Object) (controllertesting.MockHandled, error) { - return controllertesting.Handled, errors.New("test-induced-error") - }, - }, - }, - WantPresent: []runtime.Object{ - getSourceWithSink(), - }, - WantErrMsg: "test-induced-error", - }, { - Name: "successful create", - InitialState: []runtime.Object{ - getSource(), - getAddressable(), - }, - WantPresent: []runtime.Object{ - getReadySource(), - }, - }, { - Name: "successful create - reuse existing receive adapter", - InitialState: []runtime.Object{ - getSource(), - getAddressable(), - getReceiveAdapter(), - }, - Mocks: controllertesting.Mocks{ - MockCreates: []controllertesting.MockCreate{ - func(_ client.Client, _ context.Context, _ runtime.Object) (controllertesting.MockHandled, error) { - return controllertesting.Handled, errors.New("an error that won't be seen because create is not called") - }, - }, - }, - WantPresent: []runtime.Object{ - getReadySource(), - }, + Name: "key not found", + // Make sure Reconcile handles good keys that don't exist. + Key: "foo/not-found", + //}, { // TODO: there is a bug in the controller, it will query for "" + // Name: "incomplete subscription", + // Objects: []runtime.Object{ + // NewSubscription(subscriptionName, testNS), + // }, + // Key: "foo/incomplete", + // WantErr: true, + // WantEvents: []string{ + // Eventf(corev1.EventTypeWarning, "ChannelReferenceFetchFailed", "Failed to validate spec.channel exists: s \"\" not found"), + // }, }, } - for _, tc := range testCases { - tc.IgnoreTimes = true - tc.ReconcileKey = fmt.Sprintf("%s/%s", testNS, sourceName) - if tc.Reconciles == nil { - tc.Reconciles = getSource() + + defer logtesting.ClearAll() + table.Test(t, MakeFactory(func(listers *Listers, opt reconciler.Options) controller.Reconciler { + return &Reconciler{ + Base: reconciler.NewBase(opt, controllerAgentName), + cronjobLister: listers.GetCronJobSourceLister(), + deploymentLister: listers.GetDeploymentLister(), } - tc.Scheme = scheme.Scheme + })) + +} - c := tc.GetClient() - r := &reconciler{ - client: c, - scheme: tc.Scheme, +func TestNew(t *testing.T) { + defer logtesting.ClearAll() + kubeClient := fakekubeclientset.NewSimpleClientset() + eventingClient := fakeclientset.NewSimpleClientset() + eventingInformer := informers.NewSharedInformerFactory(eventingClient, 0) + kubeInformer := kubeinformers.NewSharedInformerFactory(kubeClient, 0) - receiveAdapterImage: raImage, - } - r.InjectClient(c) - t.Run(tc.Name, tc.Runner(t, r, c)) + cronjobInformer := eventingInformer.Sources().V1alpha1().CronJobSources() + deploymentInformer := kubeInformer.Apps().V1().Deployments() + + c := NewController(reconciler.Options{ + KubeClientSet: kubeClient, + EventingClientSet: eventingClient, + Logger: logtesting.TestLogger(t), + }, + cronjobInformer, + deploymentInformer, + ) + + if c == nil { + t.Fatal("Expected NewController to return a non-nil value") } } +// +//Name: "not a Cron Job source", +// Name: "invalid schedule", +// Name: "cannot get sinkURI", +// +// Name: "cannot create receive adapter", +// Name: "cannot list deployments", +// Name: "successful create", +// Name: "successful create - reuse existing receive adapter", +// + func getNonCronJobSource() *sourcesv1alpha1.ContainerSource { obj := &sourcesv1alpha1.ContainerSource{ TypeMeta: metav1.TypeMeta{ @@ -288,7 +262,7 @@ func getReceiveAdapter() *v1.Deployment { UID: sourceUID, }, }, - Labels: getLabels(getSource()), + Labels: resources.Labels(getSource().Name), Namespace: testNS, }, TypeMeta: metav1.TypeMeta{ diff --git a/pkg/reconciler/testing/listers.go b/pkg/reconciler/testing/listers.go index 814135227c2..bdd999a19d0 100644 --- a/pkg/reconciler/testing/listers.go +++ b/pkg/reconciler/testing/listers.go @@ -18,8 +18,10 @@ package testing import ( eventingv1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" + sourcesv1alpha1 "github.com/knative/eventing/pkg/apis/sources/v1alpha1" fakeeventingclientset "github.com/knative/eventing/pkg/client/clientset/versioned/fake" eventinglisters "github.com/knative/eventing/pkg/client/listers/eventing/v1alpha1" + sourcelisters "github.com/knative/eventing/pkg/client/listers/sources/v1alpha1" istiov1alpha3 "github.com/knative/pkg/apis/istio/v1alpha3" fakesharedclientset "github.com/knative/pkg/client/clientset/versioned/fake" istiolisters "github.com/knative/pkg/client/listers/istio/v1alpha3" @@ -102,6 +104,10 @@ func (l *Listers) GetVirtualServiceLister() istiolisters.VirtualServiceLister { return istiolisters.NewVirtualServiceLister(l.indexerFor(&istiov1alpha3.VirtualService{})) } +func (l *Listers) GetCronJobSourceLister() sourcelisters.CronJobSourceLister { + return sourcelisters.NewCronJobSourceLister(l.indexerFor(&sourcesv1alpha1.CronJobSource{})) +} + // GetGatewayLister gets lister for Istio Gateway resource. func (l *Listers) GetGatewayLister() istiolisters.GatewayLister { return istiolisters.NewGatewayLister(l.indexerFor(&istiov1alpha3.Gateway{})) From f9c7b2a5484e4a1f78912956fb568d849e6f32a4 Mon Sep 17 00:00:00 2001 From: Scott Nichols Date: Wed, 24 Apr 2019 08:24:00 -0700 Subject: [PATCH 06/25] working cron job source. --- cmd/controller/main.go | 28 +- .../sources/v1alpha1/cron_job_lifecycle.go | 1 + pkg/apis/sources/v1alpha1/cron_job_types.go | 2 + pkg/reconciler/cronjobsource/cronjobsource.go | 31 +- .../cronjobsource/cronjobsource_test.go | 362 +++++++++--------- .../resources/receive_adapter_test.go | 8 + pkg/reconciler/testing/cronjobsource.go | 81 ++++ pkg/reconciler/trigger/trigger.go | 4 +- 8 files changed, 318 insertions(+), 199 deletions(-) create mode 100644 pkg/reconciler/testing/cronjobsource.go diff --git a/cmd/controller/main.go b/cmd/controller/main.go index df7cdf7b2f5..7b67ccdce58 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/reconciler/cronjobsource" "log" "net/http" "os" @@ -96,7 +97,7 @@ func startPkgController(stopCh <-chan struct{}, cfg *rest.Config, logger *zap.Su logger = logger.With(zap.String("controller/impl", "pkg")) logger.Info("Starting the controller") - const numControllers = 3 + const numControllers = 4 cfg.QPS = numControllers * rest.DefaultQPS cfg.Burst = numControllers * rest.DefaultBurst opt := reconciler.NewOptionsOrDie(cfg, logger, stopCh) @@ -104,15 +105,16 @@ func startPkgController(stopCh <-chan struct{}, cfg *rest.Config, logger *zap.Su kubeInformerFactory := kubeinformers.NewSharedInformerFactory(opt.KubeClientSet, opt.ResyncPeriod) eventingInformerFactory := informers.NewSharedInformerFactory(opt.EventingClientSet, opt.ResyncPeriod) + // Eventing triggerInformer := eventingInformerFactory.Eventing().V1alpha1().Triggers() channelInformer := eventingInformerFactory.Eventing().V1alpha1().Channels() subscriptionInformer := eventingInformerFactory.Eventing().V1alpha1().Subscriptions() brokerInformer := eventingInformerFactory.Eventing().V1alpha1().Brokers() - coreServiceInformer := kubeInformerFactory.Core().V1().Services() + cronjobsourceInformer := eventingInformerFactory.Sources().V1alpha1().CronJobSources() - // TODO: remove unused after done integrating all controllers. - //deploymentInformer := kubeInformerFactory.Apps().V1().Deployments() - //coreServiceInformer := kubeInformerFactory.Core().V1().Services() + // Kube + coreServiceInformer := kubeInformerFactory.Core().V1().Services() + deploymentInformer := kubeInformerFactory.Apps().V1().Deployments() configMapInformer := kubeInformerFactory.Core().V1().ConfigMaps() // Build all of our controllers, with the clients constructed above. @@ -135,6 +137,11 @@ func startPkgController(stopCh <-chan struct{}, cfg *rest.Config, logger *zap.Su brokerInformer, coreServiceInformer, ), + cronjobsource.NewController( + opt, + cronjobsourceInformer, + deploymentInformer, + ), } if len(controllers) != numControllers { logger.Fatalf("Number of controllers and QPS settings mismatch: %d != %d", len(controllers), numControllers) @@ -152,13 +159,16 @@ func startPkgController(stopCh <-chan struct{}, cfg *rest.Config, logger *zap.Su logger.Info("Starting informers.") if err := kncontroller.StartInformers( stopCh, - subscriptionInformer.Informer(), + // Eventing + brokerInformer.Informer(), channelInformer.Informer(), - configMapInformer.Informer(), + cronjobsourceInformer.Informer(), + subscriptionInformer.Informer(), triggerInformer.Informer(), - channelInformer.Informer(), - brokerInformer.Informer(), + // Kube + configMapInformer.Informer(), coreServiceInformer.Informer(), + deploymentInformer.Informer(), ); err != nil { logger.Fatalf("Failed to start informers: %v", err) } diff --git a/pkg/apis/sources/v1alpha1/cron_job_lifecycle.go b/pkg/apis/sources/v1alpha1/cron_job_lifecycle.go index 3df28a080df..c51d6d4feec 100644 --- a/pkg/apis/sources/v1alpha1/cron_job_lifecycle.go +++ b/pkg/apis/sources/v1alpha1/cron_job_lifecycle.go @@ -54,6 +54,7 @@ func (s *CronJobSourceStatus) InitializeConditions() { cronJobSourceCondSet.Manage(s).InitializeConditions() } +// TODO: this is a bad method name, change it. // MarkSchedule sets the condition that the source has a valid schedule configured. func (s *CronJobSourceStatus) MarkSchedule() { cronJobSourceCondSet.Manage(s).MarkTrue(CronJobConditionValidSchedule) diff --git a/pkg/apis/sources/v1alpha1/cron_job_types.go b/pkg/apis/sources/v1alpha1/cron_job_types.go index 4308730c295..1bfb7957355 100644 --- a/pkg/apis/sources/v1alpha1/cron_job_types.go +++ b/pkg/apis/sources/v1alpha1/cron_job_types.go @@ -29,6 +29,8 @@ import ( // +genclient // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// TODO: We should add defaults and validation. + // CronJobSource is the Schema for the cronjobsources API. type CronJobSource struct { metav1.TypeMeta `json:",inline"` diff --git a/pkg/reconciler/cronjobsource/cronjobsource.go b/pkg/reconciler/cronjobsource/cronjobsource.go index 22f3bbb855a..488f144ca5b 100644 --- a/pkg/reconciler/cronjobsource/cronjobsource.go +++ b/pkg/reconciler/cronjobsource/cronjobsource.go @@ -21,6 +21,7 @@ import ( "fmt" "os" "reflect" + "sync" "time" appsv1 "k8s.io/api/apps/v1" @@ -67,6 +68,7 @@ type Reconciler struct { *reconciler.Base receiveAdapterImage string + once sync.Once // listers index properties about resources cronjobLister listers.CronJobSourceLister @@ -83,16 +85,10 @@ func NewController( cronjobsourceInformer sourceinformers.CronJobSourceInformer, deploymentInformer appsv1informers.DeploymentInformer, ) *controller.Impl { - raImage, defined := os.LookupEnv(raImageEnvVar) - if !defined { - panic(fmt.Errorf("required environment variable %q not defined", raImageEnvVar)) - } - r := &Reconciler{ - Base: reconciler.NewBase(opt, controllerAgentName), - receiveAdapterImage: raImage, - cronjobLister: cronjobsourceInformer.Lister(), - deploymentLister: deploymentInformer.Lister(), + Base: reconciler.NewBase(opt, controllerAgentName), + cronjobLister: cronjobsourceInformer.Lister(), + deploymentLister: deploymentInformer.Lister(), } impl := controller.NewImpl(r, r.Logger, ReconcilerName, reconciler.MustNewStatsReporter(ReconcilerName, r.Logger)) @@ -138,7 +134,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, key string) error { logging.FromContext(ctx).Warn("Error reconciling CronJobSource", zap.Error(err)) } else { logging.FromContext(ctx).Debug("CronJobSource reconciled") - r.Recorder.Eventf(cronjob, corev1.EventTypeNormal, cronjobReconciled, "CronJobSource reconciled: %q", cronjob.Name) + r.Recorder.Eventf(cronjob, corev1.EventTypeNormal, cronjobReconciled, `CronJobSource reconciled: "%s/%s"`, cronjob.Namespace, cronjob.Name) } if _, updateStatusErr := r.updateStatus(ctx, cronjob.DeepCopy()); updateStatusErr != nil { @@ -182,6 +178,19 @@ func (r *Reconciler) reconcile(ctx context.Context, cronjob *v1alpha1.CronJobSou return nil } +func (r *Reconciler) getReceiveAdapterImage() string { + if r.receiveAdapterImage == "" { + r.once.Do(func() { + raImage, defined := os.LookupEnv(raImageEnvVar) + if !defined { + panic(fmt.Errorf("required environment variable %q not defined", raImageEnvVar)) + } + r.receiveAdapterImage = raImage + }) + } + return r.receiveAdapterImage +} + func (r *Reconciler) createReceiveAdapter(ctx context.Context, src *v1alpha1.CronJobSource, sinkURI string) (*appsv1.Deployment, error) { ra, err := r.getReceiveAdapter(ctx, src) if err != nil && !apierrors.IsNotFound(err) { @@ -189,7 +198,7 @@ func (r *Reconciler) createReceiveAdapter(ctx context.Context, src *v1alpha1.Cro return nil, err } adapterArgs := resources.ReceiveAdapterArgs{ - Image: r.receiveAdapterImage, + Image: r.getReceiveAdapterImage(), Source: src, Labels: resources.Labels(src.Name), SinkURI: sinkURI, diff --git a/pkg/reconciler/cronjobsource/cronjobsource_test.go b/pkg/reconciler/cronjobsource/cronjobsource_test.go index 2cefb5f393e..a971cb1e4e9 100644 --- a/pkg/reconciler/cronjobsource/cronjobsource_test.go +++ b/pkg/reconciler/cronjobsource/cronjobsource_test.go @@ -17,13 +17,14 @@ limitations under the License. package cronjobsource import ( - //"context" - //"errors" - "fmt" "github.com/knative/eventing/pkg/reconciler/cronjobsource/resources" + "github.com/knative/eventing/pkg/utils" + "k8s.io/apimachinery/pkg/runtime" "os" "testing" + clientgotesting "k8s.io/client-go/testing" + fakeclientset "github.com/knative/eventing/pkg/client/clientset/versioned/fake" informers "github.com/knative/eventing/pkg/client/informers/externalversions" "github.com/knative/eventing/pkg/reconciler" @@ -40,9 +41,8 @@ import ( . "github.com/knative/eventing/pkg/reconciler/testing" . "github.com/knative/pkg/reconciler/testing" - sourcesv1alpha1 "github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1" + sourcesv1alpha1 "github.com/knative/eventing/pkg/apis/sources/v1alpha1" v1 "k8s.io/api/apps/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" ) var ( @@ -51,11 +51,22 @@ var ( deletionTime = metav1.Now().Rfc3339Copy() trueVal = true + + sinkGVK = metav1.GroupVersionKind{ + Group: "eventing.knative.dev", + Version: "v1alpha1", + Kind: "Channel", + } + sinkRef = corev1.ObjectReference{ + Name: sinkName, + Kind: "Channel", + APIVersion: "eventing.knative.dev/v1alpha1", + } + sinkDNS = "sink.mynamespace.svc." + utils.GetClusterDomainName() + sinkURI = "http://" + sinkDNS + "/" ) const ( - raImage = "test-ra-image" - image = "github.com/knative/test/image" sourceName = "test-cronjob-source" sourceUID = "1234-5678-90" @@ -63,11 +74,7 @@ const ( testSchedule = "*/2 * * * *" testData = "data" - addressableName = "testsink" - addressableKind = "Sink" - addressableAPIVersion = "duck.knative.dev/v1alpha1" - addressableDNS = "sinkable.sink.svc.cluster.local" - addressableURI = "http://sinkable.sink.svc.cluster.local/" + sinkName = "testsink" ) func init() { @@ -76,7 +83,7 @@ func init() { _ = corev1.AddToScheme(scheme.Scheme) _ = duckv1alpha1.AddToScheme(scheme.Scheme) - _ = os.Setenv("CRONJOB_RA_IMAGE", "no-op") + _ = os.Setenv("CRONJOB_RA_IMAGE", image) } func TestAllCases(t *testing.T) { @@ -89,16 +96,154 @@ func TestAllCases(t *testing.T) { Name: "key not found", // Make sure Reconcile handles good keys that don't exist. Key: "foo/not-found", - //}, { // TODO: there is a bug in the controller, it will query for "" - // Name: "incomplete subscription", - // Objects: []runtime.Object{ - // NewSubscription(subscriptionName, testNS), - // }, - // Key: "foo/incomplete", - // WantErr: true, - // WantEvents: []string{ - // Eventf(corev1.EventTypeWarning, "ChannelReferenceFetchFailed", "Failed to validate spec.channel exists: s \"\" not found"), - // }, + }, { + Name: "invalid schedule", + Objects: []runtime.Object{ + NewCronSourceJob(sourceName, testNS, + WithCronJobSourceSpec(sourcesv1alpha1.CronJobSourceSpec{ + Schedule: "invalid schedule", + Data: testData, + Sink: &sinkRef, + }), + ), + }, + Key: testNS + "/" + sourceName, + WantErr: true, + //WantEvents: []string{ + // Eventf(corev1.EventTypeWarning, "Fail", ""), // TODO: BUGBUGBUG This should make an event. + //}, + WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ + Object: NewCronSourceJob(sourceName, testNS, + WithCronJobSourceSpec(sourcesv1alpha1.CronJobSourceSpec{ + Schedule: "invalid schedule", + Data: testData, + Sink: &sinkRef, + }), + // Status Update: + WithInitCronJobSourceConditions, + WithInvalidCronJobSourceSchedule, + ), + }}, + }, { + Name: "missing sink", + Objects: []runtime.Object{ + NewCronSourceJob(sourceName, testNS, + WithCronJobSourceSpec(sourcesv1alpha1.CronJobSourceSpec{ + Schedule: testSchedule, + Data: testData, + Sink: &sinkRef, + }), + ), + }, + Key: testNS + "/" + sourceName, + WantErr: true, + WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ + Object: NewCronSourceJob(sourceName, testNS, + WithCronJobSourceSpec(sourcesv1alpha1.CronJobSourceSpec{ + Schedule: testSchedule, + Data: testData, + Sink: &sinkRef, + }), + // Status Update: + WithInitCronJobSourceConditions, + WithValidCronJobSourceSchedule, + WithCronJobSourceSinkNotFound, + ), + }}, + }, { + Name: "valid", + Objects: []runtime.Object{ + NewCronSourceJob(sourceName, testNS, + WithCronJobSourceSpec(sourcesv1alpha1.CronJobSourceSpec{ + Schedule: testSchedule, + Data: testData, + Sink: &sinkRef, + }), + ), + NewChannel(sinkName, testNS, + WithInitChannelConditions, + WithChannelAddress(sinkDNS), + ), + }, + Key: testNS + "/" + sourceName, + WantEvents: []string{ + Eventf(corev1.EventTypeNormal, "CronJobSourceReconciled", `CronJobSource reconciled: "%s/%s"`, testNS, sourceName), + }, + WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ + Object: NewCronSourceJob(sourceName, testNS, + WithCronJobSourceSpec(sourcesv1alpha1.CronJobSourceSpec{ + Schedule: testSchedule, + Data: testData, + Sink: &sinkRef, + }), + // Status Update: + WithInitCronJobSourceConditions, + WithValidCronJobSourceSchedule, + WithCronJobSourceDeployed, + WithCronJobSourceSink(sinkURI), + ), + }}, + WantCreates: []metav1.Object{ + makeReceiveAdapter(), + }, + }, { + Name: "valid, existing ra", + Objects: []runtime.Object{ + NewCronSourceJob(sourceName, testNS, + WithCronJobSourceSpec(sourcesv1alpha1.CronJobSourceSpec{ + Schedule: testSchedule, + Data: testData, + Sink: &sinkRef, + }), + ), + NewChannel(sinkName, testNS, + WithInitChannelConditions, + WithChannelAddress(sinkDNS), + ), + makeReceiveAdapter(), + }, + Key: testNS + "/" + sourceName, + WantEvents: []string{ + Eventf(corev1.EventTypeNormal, "CronJobSourceReconciled", `CronJobSource reconciled: "%s/%s"`, testNS, sourceName), + }, + WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ + Object: NewCronSourceJob(sourceName, testNS, + WithCronJobSourceSpec(sourcesv1alpha1.CronJobSourceSpec{ + Schedule: testSchedule, + Data: testData, + Sink: &sinkRef, + }), + // Status Update: + WithInitCronJobSourceConditions, + WithValidCronJobSourceSchedule, + WithCronJobSourceDeployed, + WithCronJobSourceSink(sinkURI), + ), + }}, + }, { + Name: "valid, no change", + Objects: []runtime.Object{ + NewCronSourceJob(sourceName, testNS, + WithCronJobSourceSpec(sourcesv1alpha1.CronJobSourceSpec{ + Schedule: testSchedule, + Data: testData, + Sink: &sinkRef, + }), + WithInitCronJobSourceConditions, + WithValidCronJobSourceSchedule, + WithCronJobSourceDeployed, + WithCronJobSourceSink(sinkURI), + ), + NewChannel(sinkName, testNS, + WithInitChannelConditions, + WithChannelAddress(sinkDNS), + ), + makeReceiveAdapter(), + }, + Key: testNS + "/" + sourceName, + WantEvents: []string{ + Eventf(corev1.EventTypeNormal, "CronJobSourceReconciled", `CronJobSource reconciled: "%s/%s"`, testNS, sourceName), + }, }, } @@ -137,163 +282,26 @@ func TestNew(t *testing.T) { } } -// -//Name: "not a Cron Job source", -// Name: "invalid schedule", -// Name: "cannot get sinkURI", -// -// Name: "cannot create receive adapter", -// Name: "cannot list deployments", -// Name: "successful create", -// Name: "successful create - reuse existing receive adapter", -// - -func getNonCronJobSource() *sourcesv1alpha1.ContainerSource { - obj := &sourcesv1alpha1.ContainerSource{ - TypeMeta: metav1.TypeMeta{ - APIVersion: sourcesv1alpha1.SchemeGroupVersion.String(), - Kind: "ContainerSource", - }, - ObjectMeta: om(testNS, sourceName), - Spec: sourcesv1alpha1.ContainerSourceSpec{ - Image: image, - Args: []string(nil), - Sink: &corev1.ObjectReference{ - Name: addressableName, - Kind: addressableKind, - APIVersion: addressableAPIVersion, - }, - }, - } - // selflink is not filled in when we create the object, so clear it - obj.ObjectMeta.SelfLink = "" - return obj -} - -func getSource() *sourcesv1alpha1.CronJobSource { - obj := &sourcesv1alpha1.CronJobSource{ - TypeMeta: metav1.TypeMeta{ - APIVersion: sourcesv1alpha1.SchemeGroupVersion.String(), - Kind: "CronJobSource", - }, - ObjectMeta: om(testNS, sourceName), - Spec: sourcesv1alpha1.CronJobSourceSpec{ +func makeReceiveAdapter() *v1.Deployment { + source := NewCronSourceJob(sourceName, testNS, + WithCronJobSourceSpec(sourcesv1alpha1.CronJobSourceSpec{ Schedule: testSchedule, Data: testData, - Sink: &corev1.ObjectReference{ - Name: addressableName, - Kind: addressableKind, - APIVersion: addressableAPIVersion, - }, + Sink: &sinkRef, }, - } - // selflink is not filled in when we create the object, so clear it - obj.ObjectMeta.SelfLink = "" - return obj -} - -func getDeletingSource() *sourcesv1alpha1.CronJobSource { - src := getSource() - src.DeletionTimestamp = &deletionTime - return src -} - -func getSourceWithInvalidSchedule() *sourcesv1alpha1.CronJobSource { - src := getSource() - src.Spec.Schedule = "invalid schedule" - return src -} - -func getSourceWithoutSink() *sourcesv1alpha1.CronJobSource { - src := getSource() - src.Status.InitializeConditions() - src.Status.MarkSchedule() - src.Status.MarkNoSink("NotFound", "") - return src -} - -func getSourceWithSink() *sourcesv1alpha1.CronJobSource { - src := getSource() - src.Status.InitializeConditions() - src.Status.MarkSchedule() - src.Status.MarkSink(addressableURI) - return src -} - -func getReadySource() *sourcesv1alpha1.CronJobSource { - src := getSourceWithSink() - src.Status.MarkDeployed() - return src -} - -func om(namespace, name string) metav1.ObjectMeta { - return metav1.ObjectMeta{ - Namespace: namespace, - Name: name, - SelfLink: fmt.Sprintf("/apis/eventing/sources/v1alpha1/namespaces/%s/object/%s", namespace, name), - UID: sourceUID, - } -} - -func getAddressable() *unstructured.Unstructured { - return &unstructured.Unstructured{ - Object: map[string]interface{}{ - "apiVersion": addressableAPIVersion, - "kind": addressableKind, - "metadata": map[string]interface{}{ - "namespace": testNS, - "name": addressableName, - }, - "status": map[string]interface{}{ - "address": map[string]interface{}{ - "hostname": addressableDNS, - }, - }, - }, - } -} + ), + // Status Update: + WithInitCronJobSourceConditions, + WithValidCronJobSourceSchedule, + WithCronJobSourceDeployed, + WithCronJobSourceSink(sinkURI), + ) -func getReceiveAdapter() *v1.Deployment { - return &v1.Deployment{ - ObjectMeta: metav1.ObjectMeta{ - OwnerReferences: []metav1.OwnerReference{ - { - Controller: &trueVal, - UID: sourceUID, - }, - }, - Labels: resources.Labels(getSource().Name), - Namespace: testNS, - }, - TypeMeta: metav1.TypeMeta{ - APIVersion: corev1.SchemeGroupVersion.String(), - Kind: "Deployment", - }, - Spec: v1.DeploymentSpec{ - Template: corev1.PodTemplateSpec{ - Spec: corev1.PodSpec{ - Containers: []corev1.Container{ - { - Name: "receive-adapter", - Image: raImage, - Env: []corev1.EnvVar{ - { - Name: "SCHEDULE", - Value: testSchedule, - }, - { - Name: "DATA", - Value: testData, - }, - { - Name: "SINK_URI", - Value: addressableURI, - }, - }, - }, - }, - }, - }, - }, + args := resources.ReceiveAdapterArgs{ + Image: image, + Source: source, + Labels: resources.Labels(sourceName), + SinkURI: sinkURI, } + return resources.MakeReceiveAdapter(&args) } diff --git a/pkg/reconciler/cronjobsource/resources/receive_adapter_test.go b/pkg/reconciler/cronjobsource/resources/receive_adapter_test.go index 6bf75683b95..e8b2c5fd1df 100644 --- a/pkg/reconciler/cronjobsource/resources/receive_adapter_test.go +++ b/pkg/reconciler/cronjobsource/resources/receive_adapter_test.go @@ -51,6 +51,7 @@ func TestMakeReceiveAdapter(t *testing.T) { }) one := int32(1) + yes := true want := &v1.Deployment{ ObjectMeta: metav1.ObjectMeta{ Namespace: "source-namespace", @@ -59,6 +60,13 @@ func TestMakeReceiveAdapter(t *testing.T) { "test-key1": "test-value1", "test-key2": "test-value2", }, + OwnerReferences: []metav1.OwnerReference{{ + APIVersion: "sources.eventing.knative.dev/v1alpha1", + Kind: "CronJobSource", + Name: "source-name", + Controller: &yes, + BlockOwnerDeletion: &yes, + }}, }, Spec: v1.DeploymentSpec{ Selector: &metav1.LabelSelector{ diff --git a/pkg/reconciler/testing/cronjobsource.go b/pkg/reconciler/testing/cronjobsource.go new file mode 100644 index 00000000000..97faf4dcf38 --- /dev/null +++ b/pkg/reconciler/testing/cronjobsource.go @@ -0,0 +1,81 @@ +/* +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 ( + "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/knative/eventing/pkg/apis/sources/v1alpha1" +) + +// CronJobSourceOption enables further configuration of a CronJob. +type CronJobSourceOption func(*v1alpha1.CronJobSource) + +// NewCronJob creates a CronJob with CronJobOptions +func NewCronSourceJob(name, namespace string, o ...CronJobSourceOption) *v1alpha1.CronJobSource { + c := &v1alpha1.CronJobSource{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + }, + } + for _, opt := range o { + opt(c) + } + //c.SetDefaults(context.Background()) // TODO: We should add defaults and validation. + return c +} + +// WithInitCronJobConditions initializes the CronJobSource's conditions. +func WithInitCronJobSourceConditions(s *v1alpha1.CronJobSource) { + s.Status.InitializeConditions() +} + +func WithValidCronJobSourceSchedule(s *v1alpha1.CronJobSource) { + s.Status.MarkSchedule() +} + +func WithInvalidCronJobSourceSchedule(s *v1alpha1.CronJobSource) { + s.Status.MarkInvalidSchedule("Invalid", "") +} + +func WithCronJobSourceSinkNotFound(s *v1alpha1.CronJobSource) { + s.Status.MarkNoSink("NotFound", "") +} + +func WithCronJobSourceSink(uri string) CronJobSourceOption { + return func(s *v1alpha1.CronJobSource) { + s.Status.MarkSink(uri) + } +} + +func WithCronJobSourceDeployed(s *v1alpha1.CronJobSource) { + s.Status.MarkDeployed() +} + +func WithCronJobSourceDeleted(c *v1alpha1.CronJobSource) { + t := metav1.NewTime(time.Unix(1e9, 0)) + c.ObjectMeta.SetDeletionTimestamp(&t) +} + +func WithCronJobSourceSpec(spec v1alpha1.CronJobSourceSpec) CronJobSourceOption { + return func(c *v1alpha1.CronJobSource) { + c.Spec = spec + } +} diff --git a/pkg/reconciler/trigger/trigger.go b/pkg/reconciler/trigger/trigger.go index d681f47274f..7924cf35e0d 100644 --- a/pkg/reconciler/trigger/trigger.go +++ b/pkg/reconciler/trigger/trigger.go @@ -26,6 +26,7 @@ import ( "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/duck" "github.com/knative/eventing/pkg/logging" "github.com/knative/eventing/pkg/reconciler" "github.com/knative/eventing/pkg/reconciler/names" @@ -33,7 +34,6 @@ import ( "github.com/knative/eventing/pkg/reconciler/trigger/resources" "github.com/knative/eventing/pkg/reconciler/v1alpha1/broker" brokerresources "github.com/knative/eventing/pkg/reconciler/v1alpha1/broker/resources" - "github.com/knative/eventing/pkg/utils/resolve" "github.com/knative/pkg/controller" "github.com/knative/pkg/tracker" "go.uber.org/zap" @@ -250,7 +250,7 @@ func (r *Reconciler) reconcile(ctx context.Context, t *v1alpha1.Trigger) error { } } - subscriberURI, err := resolve.SubscriberSpec(ctx, r.DynamicClientSet, t.Namespace, t.Spec.Subscriber) + subscriberURI, err := duck.SubscriberSpec(ctx, r.DynamicClientSet, t.Namespace, t.Spec.Subscriber) if err != nil { logging.FromContext(ctx).Error("Unable to get the Subscriber's URI", zap.Error(err)) return err From 78e021cb10b5c035509ebe5ad145ee026e25c468 Mon Sep 17 00:00:00 2001 From: Scott Nichols Date: Wed, 24 Apr 2019 08:55:03 -0700 Subject: [PATCH 07/25] add rbac --- config/200-controller-clusterrole.yaml | 46 ++++++++------------------ 1 file changed, 13 insertions(+), 33 deletions(-) diff --git a/config/200-controller-clusterrole.yaml b/config/200-controller-clusterrole.yaml index 7b0d29bca4c..955d586f7f7 100644 --- a/config/200-controller-clusterrole.yaml +++ b/config/200-controller-clusterrole.yaml @@ -26,7 +26,7 @@ rules: - "services" - "events" - "serviceaccounts" - verbs: + verbs: &everything - "get" - "list" - "create" @@ -40,42 +40,21 @@ rules: - "networking.istio.io" resources: - "virtualservices" - verbs: - - "get" - - "list" - - "create" - - "update" - - "delete" - - "patch" - - "watch" + verbs: *everything # Brokers and the namespace annotation controllers manipulate Deployments. - apiGroups: - "apps" resources: - "deployments" - verbs: - - "get" - - "list" - - "create" - - "update" - - "delete" - - "patch" - - "watch" + verbs: *everything # The namespace annotation controller needs to manipulate RoleBindings. - apiGroups: - "rbac.authorization.k8s.io" resources: - "rolebindings" - verbs: - - "get" - - "list" - - "create" - - "update" - - "delete" - - "patch" - - "watch" + verbs: *everything # Our own resources and statuses we care about. - apiGroups: @@ -91,11 +70,12 @@ rules: - "subscriptions/status" - "triggers" - "triggers/status" - verbs: - - "get" - - "list" - - "create" - - "update" - - "delete" - - "patch" - - "watch" + verbs: *everything + + # Source resources and statuses we care about. + - apiGroups: + - "sources.eventing.knative.dev" + resources: + - "cronjobsources" + - "cronjobsources/status" + verbs: *everything From a18c903258879c36a13439c138cb86423e754b33 Mon Sep 17 00:00:00 2001 From: Scott Nichols Date: Wed, 24 Apr 2019 09:04:27 -0700 Subject: [PATCH 08/25] update deps. --- Gopkg.lock | 17 - config/200-controller-clusterrole.yaml | 1 + pkg/adapter/cronjobevents/adapter.go | 7 +- .../v1alpha1/cron_job_lifecycle_test.go | 2 +- .../sources/v1alpha1/zz_generated.deepcopy.go | 10 +- .../versioned/typed/sources/v1alpha1/doc.go | 2 +- .../typed/sources/v1alpha1/fake/doc.go | 2 +- .../v1alpha1/fake/fake_sources_client.go | 7 +- .../sources/v1alpha1/generated_expansion.go | 4 +- .../typed/sources/v1alpha1/sources_client.go | 7 +- .../informers/externalversions/factory.go | 6 - .../informers/externalversions/generic.go | 5 - pkg/kncloudevents/good_client.go | 30 + third_party/VENDOR-LICENSE | 207 ------- .../knative/eventing-sources/AUTHORS | 6 - .../knative/eventing-sources/LICENSE | 201 ------- .../apis/sources/v1alpha1/aws_sqs_types.go | 154 ----- .../sources/v1alpha1/containersource_types.go | 157 ----- .../apis/sources/v1alpha1/cron_job_types.go | 164 ----- .../pkg/apis/sources/v1alpha1/doc.go | 23 - .../sources/v1alpha1/githubsource_types.go | 195 ------ .../v1alpha1/kuberneteseventsource_types.go | 122 ---- .../pkg/apis/sources/v1alpha1/register.go | 45 -- .../sources/v1alpha1/zz_generated.deepcopy.go | 562 ------------------ .../pkg/controller/sdk/finalizers_accessor.go | 82 --- .../pkg/controller/sdk/provider.go | 74 --- .../pkg/controller/sdk/reconciler.go | 186 ------ .../pkg/controller/sdk/status_accessor.go | 77 --- .../pkg/controller/testing/mock_client.go | 153 ----- .../pkg/controller/testing/table.go | 275 --------- .../pkg/kncloudevents/good_client.go | 28 - .../test/test_images/k8sevents/kodata/LICENSE | 1 - .../k8sevents/kodata/VENDOR-LICENSE | 1 - 33 files changed, 40 insertions(+), 2773 deletions(-) create mode 100644 pkg/kncloudevents/good_client.go delete mode 100644 vendor/github.com/knative/eventing-sources/AUTHORS delete mode 100644 vendor/github.com/knative/eventing-sources/LICENSE delete mode 100644 vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/aws_sqs_types.go delete mode 100644 vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/containersource_types.go delete mode 100644 vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/cron_job_types.go delete mode 100644 vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/doc.go delete mode 100644 vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/githubsource_types.go delete mode 100644 vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/kuberneteseventsource_types.go delete mode 100644 vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/register.go delete mode 100644 vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/zz_generated.deepcopy.go delete mode 100644 vendor/github.com/knative/eventing-sources/pkg/controller/sdk/finalizers_accessor.go delete mode 100644 vendor/github.com/knative/eventing-sources/pkg/controller/sdk/provider.go delete mode 100644 vendor/github.com/knative/eventing-sources/pkg/controller/sdk/reconciler.go delete mode 100644 vendor/github.com/knative/eventing-sources/pkg/controller/sdk/status_accessor.go delete mode 100644 vendor/github.com/knative/eventing-sources/pkg/controller/testing/mock_client.go delete mode 100644 vendor/github.com/knative/eventing-sources/pkg/controller/testing/table.go delete mode 100644 vendor/github.com/knative/eventing-sources/pkg/kncloudevents/good_client.go delete mode 120000 vendor/github.com/knative/eventing-sources/test/test_images/k8sevents/kodata/LICENSE delete mode 120000 vendor/github.com/knative/eventing-sources/test/test_images/k8sevents/kodata/VENDOR-LICENSE diff --git a/Gopkg.lock b/Gopkg.lock index 5380d00100c..9c0d024fa2d 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -424,20 +424,6 @@ pruneopts = "NUT" revision = "f2b4162afba35581b6d4a50d3b8f34e33c144682" -[[projects]] -<<<<<<< HEAD - digest = "1:5923fb20c8ac5e5dcc2e7a9f8dfa702c72491f3905372454add6cbb59b0e39fb" - name = "github.com/knative/eventing-sources" - packages = [ - "pkg/apis/sources/v1alpha1", - "pkg/controller/sdk", - "pkg/controller/testing", - "pkg/kncloudevents", - ] - pruneopts = "NUT" - revision = "32ce3778fa1bc46ed0b0ade16d5c57f343cafa4d" - version = "v0.5.0" - [[projects]] digest = "1:57d04562d05dd4500ff1e7e47f2e62b9be0531388377a3b691a012ce70b210d5" name = "github.com/knative/pkg" @@ -1388,9 +1374,6 @@ "github.com/google/go-cmp/cmp", "github.com/google/go-cmp/cmp/cmpopts", "github.com/google/uuid", - "github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1", - "github.com/knative/eventing-sources/pkg/controller/testing", - "github.com/knative/eventing-sources/pkg/kncloudevents", "github.com/knative/pkg/apis", "github.com/knative/pkg/apis/duck", "github.com/knative/pkg/apis/duck/v1alpha1", diff --git a/config/200-controller-clusterrole.yaml b/config/200-controller-clusterrole.yaml index 955d586f7f7..44a8d3f1408 100644 --- a/config/200-controller-clusterrole.yaml +++ b/config/200-controller-clusterrole.yaml @@ -78,4 +78,5 @@ rules: resources: - "cronjobsources" - "cronjobsources/status" + - "cronjobsources/finalizers" verbs: *everything diff --git a/pkg/adapter/cronjobevents/adapter.go b/pkg/adapter/cronjobevents/adapter.go index fb87a8cb82f..0ff3bfa9743 100644 --- a/pkg/adapter/cronjobevents/adapter.go +++ b/pkg/adapter/cronjobevents/adapter.go @@ -20,15 +20,12 @@ import ( "context" "encoding/json" - "github.com/knative/eventing-sources/pkg/kncloudevents" - "github.com/cloudevents/sdk-go/pkg/cloudevents" "github.com/cloudevents/sdk-go/pkg/cloudevents/client" "github.com/cloudevents/sdk-go/pkg/cloudevents/types" - - "github.com/robfig/cron" - + "github.com/knative/eventing/pkg/kncloudevents" "github.com/knative/pkg/logging" + "github.com/robfig/cron" "go.uber.org/zap" ) diff --git a/pkg/apis/sources/v1alpha1/cron_job_lifecycle_test.go b/pkg/apis/sources/v1alpha1/cron_job_lifecycle_test.go index bf32beed0d2..c6585c1703b 100644 --- a/pkg/apis/sources/v1alpha1/cron_job_lifecycle_test.go +++ b/pkg/apis/sources/v1alpha1/cron_job_lifecycle_test.go @@ -27,7 +27,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" - "github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1" + "github.com/knative/eventing/pkg/apis/sources/v1alpha1" duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" ) diff --git a/pkg/apis/sources/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/sources/v1alpha1/zz_generated.deepcopy.go index 27618a2b621..a6d2202a0ff 100644 --- a/pkg/apis/sources/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/sources/v1alpha1/zz_generated.deepcopy.go @@ -1,7 +1,7 @@ // +build !ignore_autogenerated /* -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. @@ -45,14 +45,6 @@ func (in *CronJobSource) DeepCopy() *CronJobSource { return out } -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *CronJobSource) 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 *CronJobSourceList) DeepCopyInto(out *CronJobSourceList) { *out = *in diff --git a/pkg/client/clientset/versioned/typed/sources/v1alpha1/doc.go b/pkg/client/clientset/versioned/typed/sources/v1alpha1/doc.go index 75445c17900..a1c6bb9fe8f 100644 --- a/pkg/client/clientset/versioned/typed/sources/v1alpha1/doc.go +++ b/pkg/client/clientset/versioned/typed/sources/v1alpha1/doc.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/client/clientset/versioned/typed/sources/v1alpha1/fake/doc.go b/pkg/client/clientset/versioned/typed/sources/v1alpha1/fake/doc.go index 128aa183a91..a00e5d7b21a 100644 --- a/pkg/client/clientset/versioned/typed/sources/v1alpha1/fake/doc.go +++ b/pkg/client/clientset/versioned/typed/sources/v1alpha1/fake/doc.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/client/clientset/versioned/typed/sources/v1alpha1/fake/fake_sources_client.go b/pkg/client/clientset/versioned/typed/sources/v1alpha1/fake/fake_sources_client.go index 14861734bd7..5fbb3e91bcb 100644 --- a/pkg/client/clientset/versioned/typed/sources/v1alpha1/fake/fake_sources_client.go +++ b/pkg/client/clientset/versioned/typed/sources/v1alpha1/fake/fake_sources_client.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,7 +19,6 @@ limitations under the License. package fake import ( - v1alpha1 "github.com/knative/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha1" rest "k8s.io/client-go/rest" testing "k8s.io/client-go/testing" ) @@ -28,10 +27,6 @@ type FakeSourcesV1alpha1 struct { *testing.Fake } -func (c *FakeSourcesV1alpha1) CronJobSources(namespace string) v1alpha1.CronJobSourceInterface { - return &FakeCronJobSources{c, namespace} -} - // RESTClient returns a RESTClient that is used to communicate // with API server by this client implementation. func (c *FakeSourcesV1alpha1) RESTClient() rest.Interface { diff --git a/pkg/client/clientset/versioned/typed/sources/v1alpha1/generated_expansion.go b/pkg/client/clientset/versioned/typed/sources/v1alpha1/generated_expansion.go index e11588db657..3d57ca700bf 100644 --- a/pkg/client/clientset/versioned/typed/sources/v1alpha1/generated_expansion.go +++ b/pkg/client/clientset/versioned/typed/sources/v1alpha1/generated_expansion.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. @@ -17,5 +17,3 @@ limitations under the License. // Code generated by client-gen. DO NOT EDIT. package v1alpha1 - -type CronJobSourceExpansion interface{} diff --git a/pkg/client/clientset/versioned/typed/sources/v1alpha1/sources_client.go b/pkg/client/clientset/versioned/typed/sources/v1alpha1/sources_client.go index ef301678c43..edbeb24bcdb 100644 --- a/pkg/client/clientset/versioned/typed/sources/v1alpha1/sources_client.go +++ b/pkg/client/clientset/versioned/typed/sources/v1alpha1/sources_client.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. @@ -27,7 +27,6 @@ import ( type SourcesV1alpha1Interface interface { RESTClient() rest.Interface - CronJobSourcesGetter } // SourcesV1alpha1Client is used to interact with features provided by the sources.eventing.knative.dev group. @@ -35,10 +34,6 @@ type SourcesV1alpha1Client struct { restClient rest.Interface } -func (c *SourcesV1alpha1Client) CronJobSources(namespace string) CronJobSourceInterface { - return newCronJobSources(c, namespace) -} - // NewForConfig creates a new SourcesV1alpha1Client for the given config. func NewForConfig(c *rest.Config) (*SourcesV1alpha1Client, error) { config := *c diff --git a/pkg/client/informers/externalversions/factory.go b/pkg/client/informers/externalversions/factory.go index c591485735a..f5f0897b7c9 100644 --- a/pkg/client/informers/externalversions/factory.go +++ b/pkg/client/informers/externalversions/factory.go @@ -26,7 +26,6 @@ import ( versioned "github.com/knative/eventing/pkg/client/clientset/versioned" eventing "github.com/knative/eventing/pkg/client/informers/externalversions/eventing" internalinterfaces "github.com/knative/eventing/pkg/client/informers/externalversions/internalinterfaces" - sources "github.com/knative/eventing/pkg/client/informers/externalversions/sources" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" schema "k8s.io/apimachinery/pkg/runtime/schema" @@ -174,13 +173,8 @@ type SharedInformerFactory interface { WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool Eventing() eventing.Interface - Sources() sources.Interface } func (f *sharedInformerFactory) Eventing() eventing.Interface { return eventing.New(f, f.namespace, f.tweakListOptions) } - -func (f *sharedInformerFactory) Sources() sources.Interface { - return sources.New(f, f.namespace, f.tweakListOptions) -} diff --git a/pkg/client/informers/externalversions/generic.go b/pkg/client/informers/externalversions/generic.go index 013b0b1e9fc..8aa9b1ad555 100644 --- a/pkg/client/informers/externalversions/generic.go +++ b/pkg/client/informers/externalversions/generic.go @@ -22,7 +22,6 @@ import ( "fmt" v1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" - sourcesv1alpha1 "github.com/knative/eventing/pkg/apis/sources/v1alpha1" schema "k8s.io/apimachinery/pkg/runtime/schema" cache "k8s.io/client-go/tools/cache" ) @@ -65,10 +64,6 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource case v1alpha1.SchemeGroupVersion.WithResource("triggers"): return &genericInformer{resource: resource.GroupResource(), informer: f.Eventing().V1alpha1().Triggers().Informer()}, nil - // Group=sources.eventing.knative.dev, Version=v1alpha1 - case sourcesv1alpha1.SchemeGroupVersion.WithResource("cronjobsources"): - return &genericInformer{resource: resource.GroupResource(), informer: f.Sources().V1alpha1().CronJobSources().Informer()}, nil - } return nil, fmt.Errorf("no informer found for %v", resource) diff --git a/pkg/kncloudevents/good_client.go b/pkg/kncloudevents/good_client.go new file mode 100644 index 00000000000..9a000dba51a --- /dev/null +++ b/pkg/kncloudevents/good_client.go @@ -0,0 +1,30 @@ +package kncloudevents + +import ( + "github.com/cloudevents/sdk-go" + "github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http" +) + +func NewDefaultClient(target ...string) (cloudevents.Client, error) { + tOpts := []http.Option{cloudevents.WithBinaryEncoding()} + if len(target) > 0 && target[0] != "" { + tOpts = append(tOpts, cloudevents.WithTarget(target[0])) + } + + // Make an http transport for the CloudEvents client. + t, err := cloudevents.NewHTTPTransport(tOpts...) + if err != nil { + return nil, err + } + + // Use the transport to make a new CloudEvents client. + c, err := cloudevents.NewClient(t, + cloudevents.WithUUIDs(), + cloudevents.WithTimeNow(), + ) + + if err != nil { + return nil, err + } + return c, nil +} diff --git a/third_party/VENDOR-LICENSE b/third_party/VENDOR-LICENSE index f882c9664f1..dcf5fffc254 100644 --- a/third_party/VENDOR-LICENSE +++ b/third_party/VENDOR-LICENSE @@ -3454,213 +3454,6 @@ SOFTWARE. -=========================================================== -Import: github.com/knative/eventing/vendor/github.com/knative/eventing-sources - - 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 diff --git a/vendor/github.com/knative/eventing-sources/AUTHORS b/vendor/github.com/knative/eventing-sources/AUTHORS deleted file mode 100644 index 9a8f2f769f4..00000000000 --- a/vendor/github.com/knative/eventing-sources/AUTHORS +++ /dev/null @@ -1,6 +0,0 @@ -# This is the list of Knative authors for copyright purposes. -# -# This does not necessarily list everyone who has contributed code, since in -# some cases, their employer may be the copyright holder. To see the full list -# of contributors, see the revision history in source control. -Google LLC diff --git a/vendor/github.com/knative/eventing-sources/LICENSE b/vendor/github.com/knative/eventing-sources/LICENSE deleted file mode 100644 index 261eeb9e9f8..00000000000 --- a/vendor/github.com/knative/eventing-sources/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - 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/knative/eventing-sources/pkg/apis/sources/v1alpha1/aws_sqs_types.go b/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/aws_sqs_types.go deleted file mode 100644 index 1f93837ce19..00000000000 --- a/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/aws_sqs_types.go +++ /dev/null @@ -1,154 +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 v1alpha1 - -import ( - "github.com/knative/pkg/apis/duck" - duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" -) - -// +genclient -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -// AwsSqsSource is the Schema for the AWS SQS API -// +k8s:openapi-gen=true -// +kubebuilder:subresource:status -// +kubebuilder:categories=all,knative,eventing,sources -type AwsSqsSource struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec AwsSqsSourceSpec `json:"spec,omitempty"` - Status AwsSqsSourceStatus `json:"status,omitempty"` -} - -// Check that AwsSqsSource can be validated and can be defaulted. -var _ runtime.Object = (*AwsSqsSource)(nil) - -// Check that AwsSqsSource implements the Conditions duck type. -var _ = duck.VerifyType(&AwsSqsSource{}, &duckv1alpha1.Conditions{}) - -// AwsSqsSourceSpec defines the desired state of the source. -type AwsSqsSourceSpec struct { - // QueueURL of the SQS queue that we will poll from. - QueueURL string `json:"queueUrl"` - - // AwsCredsSecret is the credential to use to poll the AWS SQS - AwsCredsSecret corev1.SecretKeySelector `json:"awsCredsSecret,omitempty"` - - // Sink is a reference to an object that will resolve to a domain name to - // use as the sink. This is where events will be received. - // +optional - Sink *corev1.ObjectReference `json:"sink,omitempty"` - - // ServiceAccoutName is the name of the ServiceAccount that will be used to - // run the Receive Adapter Deployment. - ServiceAccountName string `json:"serviceAccountName,omitempty"` -} - -const ( - // AwsSqsSourceConditionReady has status True when the source is - // ready to send events. - AwsSqsSourceConditionReady = duckv1alpha1.ConditionReady - - // AwsSqsSourceConditionSinkProvided has status True when the - // AwsSqsSource has been configured with a sink target. - AwsSqsSourceConditionSinkProvided duckv1alpha1.ConditionType = "SinkProvided" - - // AwsSqsSourceConditionDeployed has status True when the - // AwsSqsSource has had it's receive adapter deployment created. - AwsSqsSourceConditionDeployed duckv1alpha1.ConditionType = "Deployed" -) - -var condSet = duckv1alpha1.NewLivingConditionSet( - AwsSqsSourceConditionReady, - AwsSqsSourceConditionSinkProvided, - AwsSqsSourceConditionDeployed) - -// AwsSqsSourceStatus defines the observed state of the source. -type AwsSqsSourceStatus struct { - // 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"` - - // SinkURI is the current active sink URI that has been configured for the source. - // +optional - SinkURI string `json:"sinkUri,omitempty"` -} - -// GetCondition returns the condition currently associated with the given type, or nil. -func (s *AwsSqsSourceStatus) GetCondition(t duckv1alpha1.ConditionType) *duckv1alpha1.Condition { - return condSet.Manage(s).GetCondition(t) -} - -// IsReady returns true if the resource is ready overall. -func (s *AwsSqsSourceStatus) IsReady() bool { - return condSet.Manage(s).IsHappy() -} - -// InitializeConditions sets relevant unset conditions to Unknown state. -func (s *AwsSqsSourceStatus) InitializeConditions() { - condSet.Manage(s).InitializeConditions() -} - -// MarkSink sets the condition that the source has a sink configured. -func (s *AwsSqsSourceStatus) MarkSink(uri string) { - s.SinkURI = uri - if len(uri) > 0 { - condSet.Manage(s).MarkTrue(AwsSqsSourceConditionSinkProvided) - } else { - condSet.Manage(s).MarkUnknown(AwsSqsSourceConditionSinkProvided, - "SinkEmpty", "Sink has resolved to empty.%s", "") - } -} - -// MarkNoSink sets the condition that the source does not have a sink configured. -func (s *AwsSqsSourceStatus) MarkNoSink(reason, messageFormat string, messageA ...interface{}) { - condSet.Manage(s).MarkFalse(AwsSqsSourceConditionSinkProvided, reason, messageFormat, messageA...) -} - -// MarkDeployed sets the condition that the source has been deployed. -func (s *AwsSqsSourceStatus) MarkDeployed() { - condSet.Manage(s).MarkTrue(AwsSqsSourceConditionDeployed) -} - -// MarkDeploying sets the condition that the source is deploying. -func (s *AwsSqsSourceStatus) MarkDeploying(reason, messageFormat string, messageA ...interface{}) { - condSet.Manage(s).MarkUnknown(AwsSqsSourceConditionDeployed, reason, messageFormat, messageA...) -} - -// MarkNotDeployed sets the condition that the source has not been deployed. -func (s *AwsSqsSourceStatus) MarkNotDeployed(reason, messageFormat string, messageA ...interface{}) { - condSet.Manage(s).MarkFalse(AwsSqsSourceConditionDeployed, reason, messageFormat, messageA...) -} - -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -// AwsSqsSourceList contains a list of AwsSqsSource -type AwsSqsSourceList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []AwsSqsSource `json:"items"` -} - -func init() { - SchemeBuilder.Register(&AwsSqsSource{}, &AwsSqsSourceList{}) -} diff --git a/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/containersource_types.go b/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/containersource_types.go deleted file mode 100644 index 4492ca14690..00000000000 --- a/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/containersource_types.go +++ /dev/null @@ -1,157 +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 v1alpha1 - -import ( - "github.com/knative/pkg/apis/duck" - duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" -) - -// Check that ContainerSource can be validated and can be defaulted. -var _ runtime.Object = (*ContainerSource)(nil) - -// Check that ContainerSource implements the Conditions duck type. -var _ = duck.VerifyType(&ContainerSource{}, &duckv1alpha1.Conditions{}) - -// ContainerSourceSpec defines the desired state of ContainerSource -type ContainerSourceSpec struct { - // Image is the image to run inside of the container. - // +kubebuilder:validation:MinLength=1 - Image string `json:"image,omitempty"` - - // Args are passed to the ContainerSpec as they are. - Args []string `json:"args,omitempty"` - - // Env is the list of environment variables to set in the container. - // Cannot be updated. - // +optional - // +patchMergeKey=name - // +patchStrategy=merge - Env []corev1.EnvVar `json:"env,omitempty" patchStrategy:"merge" patchMergeKey:"name"` - - // ServiceAccountName is the name of the ServiceAccount to use to run this - // source. - // +optional - ServiceAccountName string `json:"serviceAccountName,omitempty"` - - // Sink is a reference to an object that will resolve to a domain name to use as the sink. - // +optional - Sink *corev1.ObjectReference `json:"sink,omitempty"` -} - -const ( - // ContainerSourceConditionReady has status True when the ContainerSource is ready to send events. - ContainerConditionReady = duckv1alpha1.ConditionReady - - // ContainerConditionSinkProvided has status True when the ContainerSource has been configured with a sink target. - ContainerConditionSinkProvided duckv1alpha1.ConditionType = "SinkProvided" - - // ContainerConditionDeployed has status True when the ContainerSource has had it's deployment created. - ContainerConditionDeployed duckv1alpha1.ConditionType = "Deployed" -) - -var containerCondSet = duckv1alpha1.NewLivingConditionSet( - ContainerConditionSinkProvided, - ContainerConditionDeployed) - -// ContainerSourceStatus defines the observed state of ContainerSource -type ContainerSourceStatus struct { - // 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"` - - // SinkURI is the current active sink URI that has been configured for the ContainerSource. - // +optional - SinkURI string `json:"sinkUri,omitempty"` -} - -// GetCondition returns the condition currently associated with the given type, or nil. -func (s *ContainerSourceStatus) GetCondition(t duckv1alpha1.ConditionType) *duckv1alpha1.Condition { - return containerCondSet.Manage(s).GetCondition(t) -} - -// IsReady returns true if the resource is ready overall. -func (s *ContainerSourceStatus) IsReady() bool { - return containerCondSet.Manage(s).IsHappy() -} - -// InitializeConditions sets relevant unset conditions to Unknown state. -func (s *ContainerSourceStatus) InitializeConditions() { - containerCondSet.Manage(s).InitializeConditions() -} - -// MarSink sets the condition that the source has a sink configured. -func (s *ContainerSourceStatus) MarkSink(uri string) { - s.SinkURI = uri - if len(uri) > 0 { - containerCondSet.Manage(s).MarkTrue(ContainerConditionSinkProvided) - } else { - containerCondSet.Manage(s).MarkUnknown(ContainerConditionSinkProvided, "SinkEmpty", "Sink has resolved to empty.%s", "") - } -} - -// MarkNoSink sets the condition that the source does not have a sink configured. -func (s *ContainerSourceStatus) MarkNoSink(reason, messageFormat string, messageA ...interface{}) { - containerCondSet.Manage(s).MarkFalse(ContainerConditionSinkProvided, reason, messageFormat, messageA...) -} - -// MarkDeployed sets the condition that the source has been deployed. -func (s *ContainerSourceStatus) MarkDeployed() { - containerCondSet.Manage(s).MarkTrue(ContainerConditionDeployed) -} - -// MarkDeploying sets the condition that the source is deploying. -func (s *ContainerSourceStatus) MarkDeploying(reason, messageFormat string, messageA ...interface{}) { - containerCondSet.Manage(s).MarkUnknown(ContainerConditionDeployed, reason, messageFormat, messageA...) -} - -// MarkNotDeployed sets the condition that the source has not been deployed. -func (s *ContainerSourceStatus) MarkNotDeployed(reason, messageFormat string, messageA ...interface{}) { - containerCondSet.Manage(s).MarkFalse(ContainerConditionDeployed, reason, messageFormat, messageA...) -} - -// +genclient -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -// ContainerSource is the Schema for the containersources API -// +k8s:openapi-gen=true -// +kubebuilder:subresource:status -// +kubebuilder:categories=all,knative,eventing,sources -type ContainerSource struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec ContainerSourceSpec `json:"spec,omitempty"` - Status ContainerSourceStatus `json:"status,omitempty"` -} - -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -// ContainerSourceList contains a list of ContainerSource -type ContainerSourceList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []ContainerSource `json:"items"` -} - -func init() { - SchemeBuilder.Register(&ContainerSource{}, &ContainerSourceList{}) -} diff --git a/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/cron_job_types.go b/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/cron_job_types.go deleted file mode 100644 index aaeffc74e89..00000000000 --- a/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/cron_job_types.go +++ /dev/null @@ -1,164 +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 v1alpha1 - -import ( - "github.com/knative/pkg/apis/duck" - duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" -) - -// +genclient -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -// CronJobSource is the Schema for the cronjobsources API. -// +k8s:openapi-gen=true -// +kubebuilder:subresource:status -// +kubebuilder:categories=all,knative,eventing,sources -type CronJobSource struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec CronJobSourceSpec `json:"spec,omitempty"` - Status CronJobSourceStatus `json:"status,omitempty"` -} - -// Check that CronJobSource can be validated and can be defaulted. -var _ runtime.Object = (*CronJobSource)(nil) - -// Check that CronJobSource implements the Conditions duck type. -var _ = duck.VerifyType(&CronJobSource{}, &duckv1alpha1.Conditions{}) - -// CronJobSourceSpec defines the desired state of the CronJobSource. -type CronJobSourceSpec struct { - - // Schedule is the cronjob schedule. - // +required - Schedule string `json:"schedule"` - - // Data is the data posted to the target function. - Data string `json:"data,omitempty"` - - // Sink is a reference to an object that will resolve to a domain name to use as the sink. - // +optional - Sink *corev1.ObjectReference `json:"sink,omitempty"` - - // ServiceAccoutName is the name of the ServiceAccount that will be used to run the Receive - // Adapter Deployment. - ServiceAccountName string `json:"serviceAccountName,omitempty"` -} - -const ( - // CronJobConditionReady has status True when the CronJobSource is ready to send events. - CronJobConditionReady = duckv1alpha1.ConditionReady - - // CronJobConditionValidSchedule has status True when the CronJobSource has been configured with a valid schedule. - CronJobConditionValidSchedule duckv1alpha1.ConditionType = "ValidSchedule" - - // CronJobConditionSinkProvided has status True when the CronJobSource has been configured with a sink target. - CronJobConditionSinkProvided duckv1alpha1.ConditionType = "SinkProvided" - - // CronJobConditionDeployed has status True when the CronJobSource has had it's receive adapter deployment created. - CronJobConditionDeployed duckv1alpha1.ConditionType = "Deployed" -) - -var cronJobSourceCondSet = duckv1alpha1.NewLivingConditionSet( - CronJobConditionValidSchedule, - CronJobConditionSinkProvided, - CronJobConditionDeployed) - -// CronJobSourceStatus defines the observed state of CronJobSource. -type CronJobSourceStatus struct { - // 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"` - - // SinkURI is the current active sink URI that has been configured for the CronJobSource. - // +optional - SinkURI string `json:"sinkUri,omitempty"` -} - -// GetCondition returns the condition currently associated with the given type, or nil. -func (s *CronJobSourceStatus) GetCondition(t duckv1alpha1.ConditionType) *duckv1alpha1.Condition { - return cronJobSourceCondSet.Manage(s).GetCondition(t) -} - -// IsReady returns true if the resource is ready overall. -func (s *CronJobSourceStatus) IsReady() bool { - return cronJobSourceCondSet.Manage(s).IsHappy() -} - -// InitializeConditions sets relevant unset conditions to Unknown state. -func (s *CronJobSourceStatus) InitializeConditions() { - cronJobSourceCondSet.Manage(s).InitializeConditions() -} - -// MarkSchedule sets the condition that the source has a valid schedule configured. -func (s *CronJobSourceStatus) MarkSchedule() { - cronJobSourceCondSet.Manage(s).MarkTrue(CronJobConditionValidSchedule) -} - -// MarkInvalidSchedule sets the condition that the source does not have a valid schedule configured. -func (s *CronJobSourceStatus) MarkInvalidSchedule(reason, messageFormat string, messageA ...interface{}) { - cronJobSourceCondSet.Manage(s).MarkFalse(CronJobConditionValidSchedule, reason, messageFormat, messageA...) -} - -// MarkSink sets the condition that the source has a sink configured. -func (s *CronJobSourceStatus) MarkSink(uri string) { - s.SinkURI = uri - if len(uri) > 0 { - cronJobSourceCondSet.Manage(s).MarkTrue(CronJobConditionSinkProvided) - } else { - cronJobSourceCondSet.Manage(s).MarkUnknown(CronJobConditionSinkProvided, "SinkEmpty", "Sink has resolved to empty.%s", "") - } -} - -// MarkNoSink sets the condition that the source does not have a sink configured. -func (s *CronJobSourceStatus) MarkNoSink(reason, messageFormat string, messageA ...interface{}) { - cronJobSourceCondSet.Manage(s).MarkFalse(CronJobConditionSinkProvided, reason, messageFormat, messageA...) -} - -// MarkDeployed sets the condition that the source has been deployed. -func (s *CronJobSourceStatus) MarkDeployed() { - cronJobSourceCondSet.Manage(s).MarkTrue(CronJobConditionDeployed) -} - -// MarkDeploying sets the condition that the source is deploying. -func (s *CronJobSourceStatus) MarkDeploying(reason, messageFormat string, messageA ...interface{}) { - cronJobSourceCondSet.Manage(s).MarkUnknown(CronJobConditionDeployed, reason, messageFormat, messageA...) -} - -// MarkNotDeployed sets the condition that the source has not been deployed. -func (s *CronJobSourceStatus) MarkNotDeployed(reason, messageFormat string, messageA ...interface{}) { - cronJobSourceCondSet.Manage(s).MarkFalse(CronJobConditionDeployed, reason, messageFormat, messageA...) -} - -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -// CronJobSourceList contains a list of CronJobSources. -type CronJobSourceList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []CronJobSource `json:"items"` -} - -func init() { - SchemeBuilder.Register(&CronJobSource{}, &CronJobSourceList{}) -} diff --git a/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/doc.go b/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/doc.go deleted file mode 100644 index 258a98c9176..00000000000 --- a/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/doc.go +++ /dev/null @@ -1,23 +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 v1alpha1 contains API Schema definitions for the sources v1alpha1 API group -// +k8s:openapi-gen=true -// +k8s:deepcopy-gen=package,register -// +k8s:conversion-gen=github.com/knative/eventing-sources/pkg/apis/sources -// +k8s:defaulter-gen=TypeMeta -// +groupName=sources.eventing.knative.dev -package v1alpha1 diff --git a/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/githubsource_types.go b/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/githubsource_types.go deleted file mode 100644 index 808e0fc9542..00000000000 --- a/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/githubsource_types.go +++ /dev/null @@ -1,195 +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 v1alpha1 - -import ( - "github.com/knative/pkg/apis/duck" - duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" -) - -// Check that GitHubSource can be validated and can be defaulted. -var _ runtime.Object = (*GitHubSource)(nil) - -// Check that GitHubSource implements the Conditions duck type. -var _ = duck.VerifyType(&GitHubSource{}, &duckv1alpha1.Conditions{}) - -// GitHubSourceSpec defines the desired state of GitHubSource -// +kubebuilder:categories=all,knative,eventing,sources -type GitHubSourceSpec struct { - // ServiceAccountName holds the name of the Kubernetes service account - // as which the underlying K8s resources should be run. If unspecified - // this will default to the "default" service account for the namespace - // in which the GitHubSource exists. - // +optional - ServiceAccountName string `json:"serviceAccountName,omitempty"` - - // OwnerAndRepository is the GitHub owner/org and repository to - // receive events from. The repository may be left off to receive - // events from an entire organization. - // Examples: - // myuser/project - // myorganization - // +kubebuilder:validation:MinLength=1 - OwnerAndRepository string `json:"ownerAndRepository"` - - // EventType is the type of event to receive from GitHub. These - // correspond to the "Webhook event name" values listed at - // https://developer.github.com/v3/activity/events/types/ - ie - // "pull_request" - // +kubebuilder:validation:MinItems=1 - // +kubebuilder:validation:Enum=commit_comment,create,delete,deployment,deployment_status,fork,gollum,installation,integration_installation,issue_comment,issues,label,member,membership,milestone,organization,org_block,page_build,ping,project_card,project_column,project,public,pull_request,pull_request_review,pull_request_review_comment,push,release,repository,status,team,team_add,watch - EventTypes []string `json:"eventTypes"` - - // AccessToken is the Kubernetes secret containing the GitHub - // access token - AccessToken SecretValueFromSource `json:"accessToken"` - - // SecretToken is the Kubernetes secret containing the GitHub - // secret token - SecretToken SecretValueFromSource `json:"secretToken"` - - // Sink is a reference to an object that will resolve to a domain - // name to use as the sink. - // +optional - Sink *corev1.ObjectReference `json:"sink,omitempty"` - - // API URL if using github enterprise (default https://api.github.com) - // +optional - GitHubAPIURL string `json:"githubAPIURL,omitempty"` - - // Secure can be set to true to configure the webhook to use https. - // +optional - Secure bool `json:"secure,omitempty"` -} - -// SecretValueFromSource represents the source of a secret value -type SecretValueFromSource struct { - // The Secret key to select from. - SecretKeyRef *corev1.SecretKeySelector `json:"secretKeyRef,omitempty"` -} - -const ( - // GitHubSourceEventPrefix is what all GitHub event types get - // prefixed with when converting to CloudEvent EventType - GitHubSourceEventPrefix = "dev.knative.source.github" -) - -const ( - // GitHubSourceConditionReady has status True when the - // GitHubSource is ready to send events. - GitHubSourceConditionReady = duckv1alpha1.ConditionReady - - // GitHubSourceConditionSecretsProvided has status True when the - // GitHubSource has valid secret references - GitHubSourceConditionSecretsProvided duckv1alpha1.ConditionType = "SecretsProvided" - - // GitHubSourceConditionSinkProvided has status True when the - // GitHubSource has been configured with a sink target. - GitHubSourceConditionSinkProvided duckv1alpha1.ConditionType = "SinkProvided" -) - -var gitHubSourceCondSet = duckv1alpha1.NewLivingConditionSet( - GitHubSourceConditionSecretsProvided, - GitHubSourceConditionSinkProvided) - -// GitHubSourceStatus defines the observed state of GitHubSource -type GitHubSourceStatus struct { - // 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"` - - // WebhookIDKey is the ID of the webhook registered with GitHub - WebhookIDKey string `json:"webhookIDKey,omitempty"` - - // SinkURI is the current active sink URI that has been configured - // for the GitHubSource. - // +optional - SinkURI string `json:"sinkUri,omitempty"` -} - -// GetCondition returns the condition currently associated with the given type, or nil. -func (s *GitHubSourceStatus) GetCondition(t duckv1alpha1.ConditionType) *duckv1alpha1.Condition { - return gitHubSourceCondSet.Manage(s).GetCondition(t) -} - -// IsReady returns true if the resource is ready overall. -func (s *GitHubSourceStatus) IsReady() bool { - return gitHubSourceCondSet.Manage(s).IsHappy() -} - -// InitializeConditions sets relevant unset conditions to Unknown state. -func (s *GitHubSourceStatus) InitializeConditions() { - gitHubSourceCondSet.Manage(s).InitializeConditions() -} - -// MarkSecrets sets the condition that the source has a valid spec -func (s *GitHubSourceStatus) MarkSecrets() { - gitHubSourceCondSet.Manage(s).MarkTrue(GitHubSourceConditionSecretsProvided) -} - -// MarkNoSecrets sets the condition that the source does not have a valid spec -func (s *GitHubSourceStatus) MarkNoSecrets(reason, messageFormat string, messageA ...interface{}) { - gitHubSourceCondSet.Manage(s).MarkFalse(GitHubSourceConditionSecretsProvided, reason, messageFormat, messageA...) -} - -// MarkSink sets the condition that the source has a sink configured. -func (s *GitHubSourceStatus) MarkSink(uri string) { - s.SinkURI = uri - if len(uri) > 0 { - gitHubSourceCondSet.Manage(s).MarkTrue(GitHubSourceConditionSinkProvided) - } else { - gitHubSourceCondSet.Manage(s).MarkUnknown(GitHubSourceConditionSinkProvided, - "SinkEmpty", "Sink has resolved to empty.") - } -} - -// MarkNoSink sets the condition that the source does not have a sink configured. -func (s *GitHubSourceStatus) MarkNoSink(reason, messageFormat string, messageA ...interface{}) { - gitHubSourceCondSet.Manage(s).MarkFalse(GitHubSourceConditionSinkProvided, reason, messageFormat, messageA...) -} - -// +genclient -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -// GitHubSource is the Schema for the githubsources API -// +k8s:openapi-gen=true -// +kubebuilder:subresource:status -// +kubebuilder:categories=all,knative,eventing,sources -type GitHubSource struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec GitHubSourceSpec `json:"spec,omitempty"` - Status GitHubSourceStatus `json:"status,omitempty"` -} - -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -// GitHubSourceList contains a list of GitHubSource -type GitHubSourceList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []GitHubSource `json:"items"` -} - -func init() { - SchemeBuilder.Register(&GitHubSource{}, &GitHubSourceList{}) -} diff --git a/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/kuberneteseventsource_types.go b/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/kuberneteseventsource_types.go deleted file mode 100644 index 39c5394198a..00000000000 --- a/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/kuberneteseventsource_types.go +++ /dev/null @@ -1,122 +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 v1alpha1 - -import ( - "github.com/knative/pkg/apis/duck" - duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" -) - -// Check that KubernetesEventSource can be validated and can be defaulted. -var _ runtime.Object = (*KubernetesEventSource)(nil) - -// Check that KubernetesEventSource implements the Conditions duck type. -var _ = duck.VerifyType(&KubernetesEventSource{}, &duckv1alpha1.Conditions{}) - -// KubernetesEventSourceSpec defines the desired state of the source. -type KubernetesEventSourceSpec struct { - // Namespace that we watch kubernetes events in. - Namespace string `json:"namespace"` - - // ServiceAccountName is the name of the ServiceAccount to use to run this - // source. - // +optional - ServiceAccountName string `json:"serviceAccountName,omitempty"` - - // Sink is a reference to an object that will resolve to a domain name to use - // as the sink. - // +optional - Sink *corev1.ObjectReference `json:"sink,omitempty"` -} - -const ( - // KubernetesEventSourceConditionReady has status True when the - // source is ready to send events. - KubernetesEventSourceConditionReady = duckv1alpha1.ConditionReady -) - -var kubernetesEventSourceCondSet = duckv1alpha1.NewLivingConditionSet() - -// KubernetesEventSourceStatus defines the observed state of the source. -type KubernetesEventSourceStatus struct { - // 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"` - - // SinkURI is the current active sink URI that has been configured for the source. - // +optional - SinkURI string `json:"sinkUri,omitempty"` -} - -// GetCondition returns the condition currently associated with the given type, or nil. -func (s *KubernetesEventSourceStatus) GetCondition(t duckv1alpha1.ConditionType) *duckv1alpha1.Condition { - return kubernetesEventSourceCondSet.Manage(s).GetCondition(t) -} - -// IsReady returns true if the resource is ready overall. -func (s *KubernetesEventSourceStatus) IsReady() bool { - return kubernetesEventSourceCondSet.Manage(s).IsHappy() -} - -// InitializeConditions sets relevant unset conditions to Unknown state. -func (s *KubernetesEventSourceStatus) InitializeConditions() { - kubernetesEventSourceCondSet.Manage(s).InitializeConditions() -} - -// MarkReady sets the condition that the ContainerSource owned by -// the source has Ready status True. -func (s *KubernetesEventSourceStatus) MarkReady() { - kubernetesEventSourceCondSet.Manage(s).MarkTrue(KubernetesEventSourceConditionReady) -} - -// MarkUnready sets the condition that the ContainerSource owned by -// the source does not have Ready status True. -func (s *KubernetesEventSourceStatus) MarkUnready(reason, messageFormat string, messageA ...interface{}) { - kubernetesEventSourceCondSet.Manage(s).MarkFalse(KubernetesEventSourceConditionReady, reason, messageFormat, messageA...) -} - -// +genclient -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -// KubernetesEventSource is the Schema for the kuberneteseventsources API -// +k8s:openapi-gen=true -// +kubebuilder:subresource:status -// +kubebuilder:categories=all,knative,eventing,sources -type KubernetesEventSource struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec KubernetesEventSourceSpec `json:"spec,omitempty"` - Status KubernetesEventSourceStatus `json:"status,omitempty"` -} - -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -// KubernetesEventSourceList contains a list of KubernetesEventSource -type KubernetesEventSourceList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []KubernetesEventSource `json:"items"` -} - -func init() { - SchemeBuilder.Register(&KubernetesEventSource{}, &KubernetesEventSourceList{}) -} diff --git a/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/register.go b/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/register.go deleted file mode 100644 index fa5f80118ce..00000000000 --- a/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/register.go +++ /dev/null @@ -1,45 +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. -*/ - -// NOTE: Boilerplate only. Ignore this file. - -// Package v1alpha1 contains API Schema definitions for the sources v1alpha1 API group -// +k8s:openapi-gen=true -// +k8s:deepcopy-gen=package,register -// +k8s:conversion-gen=github.com/knative/eventing-sources/pkg/apis/sources -// +k8s:defaulter-gen=TypeMeta -// +groupName=sources.eventing.knative.dev -package v1alpha1 - -import ( - "k8s.io/apimachinery/pkg/runtime/schema" - "sigs.k8s.io/controller-runtime/pkg/runtime/scheme" -) - -var ( - // SchemeGroupVersion is group version used to register these objects - SchemeGroupVersion = schema.GroupVersion{Group: "sources.eventing.knative.dev", Version: "v1alpha1"} - - // SchemeBuilder is used to add go types to the GroupVersionKind scheme - SchemeBuilder = &scheme.Builder{GroupVersion: SchemeGroupVersion} - - AddToScheme = SchemeBuilder.AddToScheme -) - -// Resource takes an unqualified resource and returns a Group qualified GroupResource -func Resource(resource string) schema.GroupResource { - return SchemeGroupVersion.WithResource(resource).GroupResource() -} diff --git a/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/zz_generated.deepcopy.go b/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/zz_generated.deepcopy.go deleted file mode 100644 index 2dbe589a81f..00000000000 --- a/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/zz_generated.deepcopy.go +++ /dev/null @@ -1,562 +0,0 @@ -// +build !ignore_autogenerated - -/* -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 deepcopy-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - v1 "k8s.io/api/core/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 *AwsSqsSource) DeepCopyInto(out *AwsSqsSource) { - *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 AwsSqsSource. -func (in *AwsSqsSource) DeepCopy() *AwsSqsSource { - if in == nil { - return nil - } - out := new(AwsSqsSource) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *AwsSqsSource) 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 *AwsSqsSourceList) DeepCopyInto(out *AwsSqsSourceList) { - *out = *in - out.TypeMeta = in.TypeMeta - out.ListMeta = in.ListMeta - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]AwsSqsSource, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AwsSqsSourceList. -func (in *AwsSqsSourceList) DeepCopy() *AwsSqsSourceList { - if in == nil { - return nil - } - out := new(AwsSqsSourceList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *AwsSqsSourceList) 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 *AwsSqsSourceSpec) DeepCopyInto(out *AwsSqsSourceSpec) { - *out = *in - in.AwsCredsSecret.DeepCopyInto(&out.AwsCredsSecret) - if in.Sink != nil { - in, out := &in.Sink, &out.Sink - *out = new(v1.ObjectReference) - **out = **in - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AwsSqsSourceSpec. -func (in *AwsSqsSourceSpec) DeepCopy() *AwsSqsSourceSpec { - if in == nil { - return nil - } - out := new(AwsSqsSourceSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *AwsSqsSourceStatus) DeepCopyInto(out *AwsSqsSourceStatus) { - *out = *in - in.Status.DeepCopyInto(&out.Status) - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AwsSqsSourceStatus. -func (in *AwsSqsSourceStatus) DeepCopy() *AwsSqsSourceStatus { - if in == nil { - return nil - } - out := new(AwsSqsSourceStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ContainerSource) DeepCopyInto(out *ContainerSource) { - *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 ContainerSource. -func (in *ContainerSource) DeepCopy() *ContainerSource { - if in == nil { - return nil - } - out := new(ContainerSource) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *ContainerSource) 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 *ContainerSourceList) DeepCopyInto(out *ContainerSourceList) { - *out = *in - out.TypeMeta = in.TypeMeta - out.ListMeta = in.ListMeta - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]ContainerSource, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ContainerSourceList. -func (in *ContainerSourceList) DeepCopy() *ContainerSourceList { - if in == nil { - return nil - } - out := new(ContainerSourceList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *ContainerSourceList) 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 *ContainerSourceSpec) DeepCopyInto(out *ContainerSourceSpec) { - *out = *in - if in.Args != nil { - in, out := &in.Args, &out.Args - *out = make([]string, len(*in)) - copy(*out, *in) - } - if in.Env != nil { - in, out := &in.Env, &out.Env - *out = make([]v1.EnvVar, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.Sink != nil { - in, out := &in.Sink, &out.Sink - *out = new(v1.ObjectReference) - **out = **in - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ContainerSourceSpec. -func (in *ContainerSourceSpec) DeepCopy() *ContainerSourceSpec { - if in == nil { - return nil - } - out := new(ContainerSourceSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ContainerSourceStatus) DeepCopyInto(out *ContainerSourceStatus) { - *out = *in - in.Status.DeepCopyInto(&out.Status) - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ContainerSourceStatus. -func (in *ContainerSourceStatus) DeepCopy() *ContainerSourceStatus { - if in == nil { - return nil - } - out := new(ContainerSourceStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *CronJobSource) DeepCopyInto(out *CronJobSource) { - *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 CronJobSource. -func (in *CronJobSource) DeepCopy() *CronJobSource { - if in == nil { - return nil - } - out := new(CronJobSource) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *CronJobSource) 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 *CronJobSourceList) DeepCopyInto(out *CronJobSourceList) { - *out = *in - out.TypeMeta = in.TypeMeta - out.ListMeta = in.ListMeta - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]CronJobSource, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CronJobSourceList. -func (in *CronJobSourceList) DeepCopy() *CronJobSourceList { - if in == nil { - return nil - } - out := new(CronJobSourceList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *CronJobSourceList) 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 *CronJobSourceSpec) DeepCopyInto(out *CronJobSourceSpec) { - *out = *in - if in.Sink != nil { - in, out := &in.Sink, &out.Sink - *out = new(v1.ObjectReference) - **out = **in - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CronJobSourceSpec. -func (in *CronJobSourceSpec) DeepCopy() *CronJobSourceSpec { - if in == nil { - return nil - } - out := new(CronJobSourceSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *CronJobSourceStatus) DeepCopyInto(out *CronJobSourceStatus) { - *out = *in - in.Status.DeepCopyInto(&out.Status) - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CronJobSourceStatus. -func (in *CronJobSourceStatus) DeepCopy() *CronJobSourceStatus { - if in == nil { - return nil - } - out := new(CronJobSourceStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *GitHubSource) DeepCopyInto(out *GitHubSource) { - *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 GitHubSource. -func (in *GitHubSource) DeepCopy() *GitHubSource { - if in == nil { - return nil - } - out := new(GitHubSource) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *GitHubSource) 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 *GitHubSourceList) DeepCopyInto(out *GitHubSourceList) { - *out = *in - out.TypeMeta = in.TypeMeta - out.ListMeta = in.ListMeta - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]GitHubSource, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GitHubSourceList. -func (in *GitHubSourceList) DeepCopy() *GitHubSourceList { - if in == nil { - return nil - } - out := new(GitHubSourceList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *GitHubSourceList) 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 *GitHubSourceSpec) DeepCopyInto(out *GitHubSourceSpec) { - *out = *in - if in.EventTypes != nil { - in, out := &in.EventTypes, &out.EventTypes - *out = make([]string, len(*in)) - copy(*out, *in) - } - in.AccessToken.DeepCopyInto(&out.AccessToken) - in.SecretToken.DeepCopyInto(&out.SecretToken) - if in.Sink != nil { - in, out := &in.Sink, &out.Sink - *out = new(v1.ObjectReference) - **out = **in - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GitHubSourceSpec. -func (in *GitHubSourceSpec) DeepCopy() *GitHubSourceSpec { - if in == nil { - return nil - } - out := new(GitHubSourceSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *GitHubSourceStatus) DeepCopyInto(out *GitHubSourceStatus) { - *out = *in - in.Status.DeepCopyInto(&out.Status) - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GitHubSourceStatus. -func (in *GitHubSourceStatus) DeepCopy() *GitHubSourceStatus { - if in == nil { - return nil - } - out := new(GitHubSourceStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *KubernetesEventSource) DeepCopyInto(out *KubernetesEventSource) { - *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 KubernetesEventSource. -func (in *KubernetesEventSource) DeepCopy() *KubernetesEventSource { - if in == nil { - return nil - } - out := new(KubernetesEventSource) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *KubernetesEventSource) 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 *KubernetesEventSourceList) DeepCopyInto(out *KubernetesEventSourceList) { - *out = *in - out.TypeMeta = in.TypeMeta - out.ListMeta = in.ListMeta - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]KubernetesEventSource, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubernetesEventSourceList. -func (in *KubernetesEventSourceList) DeepCopy() *KubernetesEventSourceList { - if in == nil { - return nil - } - out := new(KubernetesEventSourceList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *KubernetesEventSourceList) 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 *KubernetesEventSourceSpec) DeepCopyInto(out *KubernetesEventSourceSpec) { - *out = *in - if in.Sink != nil { - in, out := &in.Sink, &out.Sink - *out = new(v1.ObjectReference) - **out = **in - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubernetesEventSourceSpec. -func (in *KubernetesEventSourceSpec) DeepCopy() *KubernetesEventSourceSpec { - if in == nil { - return nil - } - out := new(KubernetesEventSourceSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *KubernetesEventSourceStatus) DeepCopyInto(out *KubernetesEventSourceStatus) { - *out = *in - in.Status.DeepCopyInto(&out.Status) - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubernetesEventSourceStatus. -func (in *KubernetesEventSourceStatus) DeepCopy() *KubernetesEventSourceStatus { - if in == nil { - return nil - } - out := new(KubernetesEventSourceStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SecretValueFromSource) DeepCopyInto(out *SecretValueFromSource) { - *out = *in - if in.SecretKeyRef != nil { - in, out := &in.SecretKeyRef, &out.SecretKeyRef - *out = new(v1.SecretKeySelector) - (*in).DeepCopyInto(*out) - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretValueFromSource. -func (in *SecretValueFromSource) DeepCopy() *SecretValueFromSource { - if in == nil { - return nil - } - out := new(SecretValueFromSource) - in.DeepCopyInto(out) - return out -} diff --git a/vendor/github.com/knative/eventing-sources/pkg/controller/sdk/finalizers_accessor.go b/vendor/github.com/knative/eventing-sources/pkg/controller/sdk/finalizers_accessor.go deleted file mode 100644 index f7545ab0d7a..00000000000 --- a/vendor/github.com/knative/eventing-sources/pkg/controller/sdk/finalizers_accessor.go +++ /dev/null @@ -1,82 +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 sdk - -import ( - "errors" - "fmt" - "reflect" - - "k8s.io/apimachinery/pkg/util/sets" -) - -// FinalizersAccessor is the interface for a Resource that implements the getter and setting for -// accessing its Finalizer set. -// +k8s:deepcopy-gen=true -type FinalizersAccessor interface { - GetFinalizers() sets.String - SetFinalizers(finalizers sets.String) -} - -// NewReflectedFinalizersAccessor uses reflection to return a FinalizersAccessor to access the field -// called "Finalizers". -func NewReflectedFinalizersAccessor(object interface{}) (FinalizersAccessor, error) { - objectValue := reflect.Indirect(reflect.ValueOf(object)) - - // If object is not a struct, don't even try to use it. - if objectValue.Kind() != reflect.Struct { - return nil, errors.New("object is not a struct") - } - - finalizersField := objectValue.FieldByName("Finalizers") - if finalizersField.IsValid() && finalizersField.CanSet() && finalizersField.Kind() == reflect.Slice { - finalizers := sets.NewString() - for i := 0; i < finalizersField.Len(); i++ { - finalizer := finalizersField.Index(i) - if finalizer.IsValid() && finalizer.Kind() == reflect.String { - finalizers.Insert(finalizer.String()) - } else { - return nil, fmt.Errorf("element in the Finalizer slice was not a string: %v", finalizer.Kind()) - } - } - return &reflectedFinalizersAccessor{ - finalizersField: finalizersField, - finalizersSet: finalizers, - }, nil - } - - return nil, fmt.Errorf("finalizer was not a slice: %v", finalizersField.Kind()) -} - -// reflectedFinalizersAccessor is an internal wrapper object to act as the FinalizersAccessor for -// objects that do not implement FinalizersAccessor directly, but do expose the field using the -// name "Finalizers". -type reflectedFinalizersAccessor struct { - finalizersField reflect.Value - finalizersSet sets.String -} - -// GetFinalizers uses reflection to return the Finalizers set from the held object. -func (r *reflectedFinalizersAccessor) GetFinalizers() sets.String { - return r.finalizersSet -} - -// SetFinalizers uses reflection to set Finalizers on the held object. -func (r *reflectedFinalizersAccessor) SetFinalizers(finalizers sets.String) { - r.finalizersSet = finalizers - r.finalizersField.Set(reflect.ValueOf(finalizers.List())) -} diff --git a/vendor/github.com/knative/eventing-sources/pkg/controller/sdk/provider.go b/vendor/github.com/knative/eventing-sources/pkg/controller/sdk/provider.go deleted file mode 100644 index 664de9daf0e..00000000000 --- a/vendor/github.com/knative/eventing-sources/pkg/controller/sdk/provider.go +++ /dev/null @@ -1,74 +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 sdk - -import ( - "context" - - "k8s.io/apimachinery/pkg/runtime" - "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/runtime/inject" - "sigs.k8s.io/controller-runtime/pkg/source" -) - -type KnativeReconciler interface { - Reconcile(ctx context.Context, object runtime.Object) error - inject.Client -} - -type Provider struct { - AgentName string - // Parent is a resource kind to reconcile with empty content. i.e. &v1.Parent{} - Parent runtime.Object - // Owns are dependent resources owned by the parent for which changes to - // those resources cause the Parent to be re-reconciled. This is a list of - // resources of kind with empty content. i.e. [&v1.Child{}] - Owns []runtime.Object - - Reconciler KnativeReconciler -} - -// ProvideController returns a controller for controller-runtime. -func (p *Provider) Add(mgr manager.Manager) error { - // Setup a new controller to Reconcile Subscriptions. - c, err := controller.New(p.AgentName, mgr, controller.Options{ - Reconciler: &Reconciler{ - provider: *p, - recorder: mgr.GetRecorder(p.AgentName), - }, - }) - if err != nil { - return err - } - - // Watch Parent events and enqueue Parent object key. - if err := c.Watch(&source.Kind{Type: p.Parent}, &handler.EnqueueRequestForObject{}); err != nil { - return err - } - - // Watch and enqueue for owning obj key. - for _, t := range p.Owns { - if err := c.Watch(&source.Kind{Type: t}, - &handler.EnqueueRequestForOwner{OwnerType: p.Parent, IsController: true}); err != nil { - return err - } - } - - return nil -} diff --git a/vendor/github.com/knative/eventing-sources/pkg/controller/sdk/reconciler.go b/vendor/github.com/knative/eventing-sources/pkg/controller/sdk/reconciler.go deleted file mode 100644 index 58d39d25122..00000000000 --- a/vendor/github.com/knative/eventing-sources/pkg/controller/sdk/reconciler.go +++ /dev/null @@ -1,186 +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 sdk - -import ( - "context" - - "go.uber.org/zap" - - "github.com/knative/pkg/logging" - "k8s.io/apimachinery/pkg/api/equality" - "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/client-go/rest" - "k8s.io/client-go/tools/record" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - "sigs.k8s.io/controller-runtime/pkg/runtime/inject" -) - -type Reconciler struct { - client client.Client - recorder record.EventRecorder - scheme *runtime.Scheme - - provider Provider -} - -// Verify the struct implements reconcile.Reconciler -var _ reconcile.Reconciler = &Reconciler{} - -// Reconcile compares the actual state with the desired, and attempts to -// converge the two. -func (r *Reconciler) Reconcile(request reconcile.Request) (reconcile.Result, error) { - ctx := context.TODO() - logger := logging.FromContext(ctx) - - logger.Infof("Reconciling %s %v", r.provider.Parent.GetObjectKind(), request) - - original := r.provider.Parent.DeepCopyObject() - - err := r.client.Get(context.TODO(), request.NamespacedName, original) - - if errors.IsNotFound(err) { - logger.Errorf("could not find %s %v\n", r.provider.Parent.GetObjectKind(), request) - return reconcile.Result{}, nil - } - - if err != nil { - logger.Errorf("could not fetch %s %v for %+v\n", r.provider.Parent.GetObjectKind(), err, request) - return reconcile.Result{}, err - } - - // Don't modify the cache's copy - obj := original.DeepCopyObject() - - // Reconcile this copy of the Source and then write back any status - // updates regardless of whether the reconcile error out. - reconcileErr := r.provider.Reconciler.Reconcile(ctx, obj) - if reconcileErr != nil { - logger.Warnf("Failed to reconcile %s: %v", r.provider.Parent.GetObjectKind(), reconcileErr) - } - - if needsUpdate, err := r.needsUpdate(ctx, original, obj); err != nil { - logger.Desugar().Error("Unable to determine if an update is needed", zap.Error(err), zap.Any("original", original), zap.Any("obj", obj)) - return reconcile.Result{}, err - } else if needsUpdate { - if _, err := r.update(ctx, request, obj); err != nil { - logger.Desugar().Error("Failed to update", zap.Error(err), zap.Any("objectKind", r.provider.Parent.GetObjectKind())) - return reconcile.Result{}, err - } - } - - // Requeue if the resource is not ready: - return reconcile.Result{}, reconcileErr -} - -func (r *Reconciler) InjectClient(c client.Client) error { - r.client = c - _, err := inject.ClientInto(c, r.provider.Reconciler) - return err -} - -func (r *Reconciler) InjectConfig(c *rest.Config) error { - _, err := inject.ConfigInto(c, r.provider.Reconciler) - return err -} - -func (r *Reconciler) needsUpdate(ctx context.Context, old, new runtime.Object) (bool, error) { - if old == nil { - return true, nil - } - - // Check Status. - os, err := NewReflectedStatusAccessor(old) - if err != nil { - return false, err - } - ns, err := NewReflectedStatusAccessor(new) - if err != nil { - return false, err - } - oStatus := os.GetStatus() - nStatus := ns.GetStatus() - - if !equality.Semantic.DeepEqual(oStatus, nStatus) { - return true, nil - } - - // Check finalizers. - of, err := NewReflectedFinalizersAccessor(old) - if err != nil { - return false, err - } - nf, err := NewReflectedFinalizersAccessor(new) - if err != nil { - return false, err - } - oFinalizers := of.GetFinalizers() - nFinalizers := nf.GetFinalizers() - - if !equality.Semantic.DeepEqual(oFinalizers, nFinalizers) { - return true, nil - } - - return false, nil -} - -func (r *Reconciler) update(ctx context.Context, request reconcile.Request, object runtime.Object) (runtime.Object, error) { - freshObj := r.provider.Parent.DeepCopyObject() - if err := r.client.Get(ctx, request.NamespacedName, freshObj); err != nil { - return nil, err - } - - // Finalizers - freshFinalizers, err := NewReflectedFinalizersAccessor(freshObj) - if err != nil { - return nil, err - } - orgFinalizers, err := NewReflectedFinalizersAccessor(object) - if err != nil { - return nil, err - } - freshFinalizers.SetFinalizers(orgFinalizers.GetFinalizers()) - - if err := r.client.Update(ctx, freshObj); err != nil { - return nil, err - } - - // Refetch - freshObj = r.provider.Parent.DeepCopyObject() - if err := r.client.Get(ctx, request.NamespacedName, freshObj); err != nil { - return nil, err - } - - // Status - freshStatus, err := NewReflectedStatusAccessor(freshObj) - if err != nil { - return nil, err - } - orgStatus, err := NewReflectedStatusAccessor(object) - if err != nil { - return nil, err - } - freshStatus.SetStatus(orgStatus.GetStatus()) - - if err := r.client.Status().Update(ctx, freshObj); err != nil { - return nil, err - } - - return freshObj, nil -} diff --git a/vendor/github.com/knative/eventing-sources/pkg/controller/sdk/status_accessor.go b/vendor/github.com/knative/eventing-sources/pkg/controller/sdk/status_accessor.go deleted file mode 100644 index f5aa7c2c18a..00000000000 --- a/vendor/github.com/knative/eventing-sources/pkg/controller/sdk/status_accessor.go +++ /dev/null @@ -1,77 +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 sdk - -import ( - "errors" - "fmt" - "reflect" -) - -// StatusAccessor is the interface for a Resource that implements the getter and -// setter for accessing a Condition collection. -// +k8s:deepcopy-gen=true -type StatusAccessor interface { - GetStatus() interface{} - SetStatus(interface{}) -} - -// NewReflectedStatusAccessor uses reflection to return a StatusAccessor -// to access the field called "Status". -func NewReflectedStatusAccessor(object interface{}) (StatusAccessor, error) { - objectValue := reflect.Indirect(reflect.ValueOf(object)) - - // If object is not a struct, don't even try to use it. - if objectValue.Kind() != reflect.Struct { - return nil, errors.New("object is not a struct") - } - - statusField := objectValue.FieldByName("Status") - - if statusField.IsValid() && statusField.CanInterface() && statusField.CanSet() { - if _, ok := statusField.Interface().(interface{}); ok { - return &reflectedStatusAccessor{ - status: statusField, - }, nil - } - } - return nil, fmt.Errorf("status was not an interface: %v", statusField.Kind()) -} - -// reflectedConditionsAccessor is an internal wrapper object to act as the -// ConditionsAccessor for status objects that do not implement ConditionsAccessor -// directly, but do expose the field using the "Conditions" field name. -type reflectedStatusAccessor struct { - status reflect.Value -} - -// GetConditions uses reflection to return Conditions from the held status object. -func (r *reflectedStatusAccessor) GetStatus() interface{} { - if r != nil && r.status.IsValid() && r.status.CanInterface() { - if status, ok := r.status.Interface().(interface{}); ok { - return status - } - } - return nil -} - -// SetConditions uses reflection to set Conditions on the held status object. -func (r *reflectedStatusAccessor) SetStatus(status interface{}) { - if r != nil && r.status.IsValid() && r.status.CanSet() { - r.status.Set(reflect.ValueOf(status)) - } -} diff --git a/vendor/github.com/knative/eventing-sources/pkg/controller/testing/mock_client.go b/vendor/github.com/knative/eventing-sources/pkg/controller/testing/mock_client.go deleted file mode 100644 index 056199bc2d4..00000000000 --- a/vendor/github.com/knative/eventing-sources/pkg/controller/testing/mock_client.go +++ /dev/null @@ -1,153 +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 testing - -import ( - "context" - - "k8s.io/apimachinery/pkg/runtime" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -type MockHandled int - -const ( - // This mock has handled the function call, no further mocks nor the real client should be - // called. - Handled MockHandled = iota - // This mock has not handled the function call, subsequent mocks or the real client should be - // called. - Unhandled -) - -// All of the funcions in client.Client get mocked equivalents. For the function -// client.Client.Foo(), the mocked equivalent will be: -// func(innerClient client.Client[, arguments to Foo()]) (MockHandled[, returns from Foo()]) - -type MockGet func(innerClient client.Client, ctx context.Context, key client.ObjectKey, obj runtime.Object) (MockHandled, error) -type MockList func(innerClient client.Client, ctx context.Context, opts *client.ListOptions, list runtime.Object) (MockHandled, error) -type MockCreate func(innerClient client.Client, ctx context.Context, obj runtime.Object) (MockHandled, error) -type MockDelete func(innerClient client.Client, ctx context.Context, obj runtime.Object) (MockHandled, error) -type MockUpdate func(innerClient client.Client, ctx context.Context, obj runtime.Object) (MockHandled, error) - -var _ client.Client = (*MockClient)(nil) - -// mockClient is a client.Client that allows mock responses to be returned, instead of calling the -// inner client.Client. -type MockClient struct { - innerClient client.Client - mocks Mocks -} - -// The mocks to run on each function type. Each function will run through the mocks in its list -// until one responds with 'Handled'. If there is more than one mock in the list, then the one that -// responds 'Handled' will be removed and not run on subsequent calls to the function. If no mocks -// respond 'Handled', then the real underlying client is called. -type Mocks struct { - MockGets []MockGet - MockLists []MockList - MockCreates []MockCreate - MockDeletes []MockDelete - MockUpdates []MockUpdate -} - -func NewMockClient(innerClient client.Client, mocks Mocks) *MockClient { - return &MockClient{ - innerClient: innerClient, - mocks: mocks, - } -} - -func (m *MockClient) stopMocking() { - m.mocks = Mocks{} -} - -// All of the functions are handled almost identically: -// 1. Run through the mocks in order: -// a. If the mock handled the request, then: -// i. If there is at least one other mock in the list, remove this mock. -// ii. Return the response from the mock. -// 2. No mock handled the request, so call the inner client. - -func (m *MockClient) Get(ctx context.Context, key client.ObjectKey, obj runtime.Object) error { - for i, mockGet := range m.mocks.MockGets { - handled, err := mockGet(m.innerClient, ctx, key, obj) - if handled == Handled { - if len(m.mocks.MockGets) > 1 { - m.mocks.MockGets = append(m.mocks.MockGets[:i], m.mocks.MockGets[i+1:]...) - } - return err - } - } - return m.innerClient.Get(ctx, key, obj) -} - -func (m *MockClient) List(ctx context.Context, opts *client.ListOptions, list runtime.Object) error { - for i, mockList := range m.mocks.MockLists { - handled, err := mockList(m.innerClient, ctx, opts, list) - if handled == Handled { - if len(m.mocks.MockLists) > 1 { - m.mocks.MockLists = append(m.mocks.MockLists[:i], m.mocks.MockLists[i+1:]...) - } - return err - } - } - return m.innerClient.List(ctx, opts, list) -} - -func (m *MockClient) Create(ctx context.Context, obj runtime.Object) error { - for i, mockCreate := range m.mocks.MockCreates { - handled, err := mockCreate(m.innerClient, ctx, obj) - if handled == Handled { - if len(m.mocks.MockCreates) > 1 { - m.mocks.MockCreates = append(m.mocks.MockCreates[:i], m.mocks.MockCreates[i+1:]...) - } - return err - } - } - return m.innerClient.Create(ctx, obj) -} - -func (m *MockClient) Delete(ctx context.Context, obj runtime.Object, opts ...client.DeleteOptionFunc) error { - for i, mockDelete := range m.mocks.MockDeletes { - handled, err := mockDelete(m.innerClient, ctx, obj) - if handled == Handled { - if len(m.mocks.MockDeletes) > 1 { - m.mocks.MockDeletes = append(m.mocks.MockDeletes[:i], m.mocks.MockDeletes[i+1:]...) - } - return err - } - } - return m.innerClient.Delete(ctx, obj, opts...) -} - -func (m *MockClient) Update(ctx context.Context, obj runtime.Object) error { - for i, mockUpdate := range m.mocks.MockUpdates { - handled, err := mockUpdate(m.innerClient, ctx, obj) - if handled == Handled { - if len(m.mocks.MockUpdates) > 1 { - m.mocks.MockUpdates = append(m.mocks.MockUpdates[:i], m.mocks.MockUpdates[i+1:]...) - } - return err - } - } - return m.innerClient.Update(ctx, obj) -} - -func (m *MockClient) Status() client.StatusWriter { - return m.innerClient.Status() -} diff --git a/vendor/github.com/knative/eventing-sources/pkg/controller/testing/table.go b/vendor/github.com/knative/eventing-sources/pkg/controller/testing/table.go deleted file mode 100644 index bb23d668bf8..00000000000 --- a/vendor/github.com/knative/eventing-sources/pkg/controller/testing/table.go +++ /dev/null @@ -1,275 +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 testing - -import ( - "context" - "fmt" - "strings" - "testing" - - "github.com/google/go-cmp/cmp" - "github.com/google/go-cmp/cmp/cmpopts" - "github.com/knative/eventing-sources/pkg/controller/sdk" - "github.com/knative/pkg/apis" - apierrors "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/api/meta" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/client-go/dynamic" - dynamicfake "k8s.io/client-go/dynamic/fake" - "k8s.io/client-go/kubernetes/scheme" - "k8s.io/client-go/tools/cache" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/client/fake" - "sigs.k8s.io/controller-runtime/pkg/reconcile" -) - -// TestCase holds a single row of our table test. -type TestCase struct { - // Name is a descriptive name for this test suitable as a first argument to t.Run() - Name string - - // InitialState is the list of objects that already exists when reconciliation - // starts. - InitialState []runtime.Object - - Reconciles runtime.Object - - // ReconcileKey is the key of the object to reconcile in namespace/name form. - ReconcileKey string - - // WantErr is true when we expect the Reconcile function to return an error. - WantErr bool - - // WantErrMsg contains the pattern to match the returned error message. - // Implies WantErr = true. - WantErrMsg string - - // WantResult is the reconcile result we expect to be returned from the - // Reconcile function. - WantResult reconcile.Result - - // WantResultObject is the reconcile result we expect to be returned from the - // Reconcile function. - WantResultObject runtime.Object - - // WantPresent holds the non-exclusive set of objects we expect to exist - // after reconciliation completes. - WantPresent []runtime.Object - - // WantAbsent holds the list of objects expected to not exist - // after reconciliation completes. - WantAbsent []runtime.Object - - // Mocks that tamper with the client's responses. - Mocks Mocks - - // Scheme for the dynamic client - Scheme *runtime.Scheme - - // Fake dynamic objects - Objects []runtime.Object - - // OtherTestData is arbitrary data needed for the test. It is not used directly by the table - // testing framework. Instead it is used in the test method. E.g. setting up the responses for a - // fake GCP PubSub client can go in here, as no other field makes sense for it. - OtherTestData map[string]interface{} - - // IgnoreTimes causes comparisons to ignore fields of type apis.VolatileTime. - IgnoreTimes bool -} - -// Runner returns a testing func that can be passed to t.Run. -func (tc *TestCase) Runner(t *testing.T, r sdk.KnativeReconciler, c *MockClient) func(t *testing.T) { - return func(t *testing.T) { - result, recErr := tc.Reconcile(c, r) - - if err := tc.VerifyErr(recErr); err != nil { - t.Error(err) - } - - // Push back the reconciled changes into the client. - if result != nil { - c.Update(context.TODO(), result) - } - - // Verifying should be done against the innerClient, never against mocks. - c.stopMocking() - - if err := tc.VerifyWantPresent(c); err != nil { - t.Error(err) - } - - if err := tc.VerifyWantAbsent(c); err != nil { - t.Error(err) - } - } -} - -// GetDynamicClient returns the mockDynamicClient to use for this test case. -func (tc *TestCase) GetDynamicClient() dynamic.Interface { - if tc.Scheme == nil { - return dynamicfake.NewSimpleDynamicClient(runtime.NewScheme(), tc.Objects...) - } - return dynamicfake.NewSimpleDynamicClient(tc.Scheme, tc.Objects...) -} - -// GetClient returns the mockClient to use for this test case. -func (tc *TestCase) GetClient() *MockClient { - innerClient := fake.NewFakeClient(tc.InitialState...) - return NewMockClient(innerClient, tc.Mocks) -} - -// Reconcile calls the given reconciler's Reconcile() function with the test -// case's reconcile request. -func (tc *TestCase) Reconcile(c client.Client, r sdk.KnativeReconciler) (runtime.Object, error) { - if tc.ReconcileKey == "" { - return nil, fmt.Errorf("test did not set ReconcileKey") - } - ns, n, err := cache.SplitMetaNamespaceKey(tc.ReconcileKey) - if err != nil { - return nil, err - } - - obj := tc.Reconciles.DeepCopyObject() - err = c.Get(context.TODO(), client.ObjectKey{Namespace: ns, Name: n}, obj) - if err != nil { - // Not found is not an error. - return nil, nil - } - - return obj, r.Reconcile(context.TODO(), obj) -} - -// VerifyErr verifies that the given error returned from Reconcile is the error -// expected by the test case. -func (tc *TestCase) VerifyErr(err error) error { - // A non-empty WantErrMsg implies that an error is wanted. - wantErr := tc.WantErr || tc.WantErrMsg != "" - - if wantErr && err == nil { - return fmt.Errorf("want error, got nil") - } - - if !wantErr && err != nil { - return fmt.Errorf("want no error, got %v", err) - } - - if err != nil { - if diff := cmp.Diff(tc.WantErrMsg, err.Error()); diff != "" { - return fmt.Errorf("incorrect error (-want, +got): %v", diff) - } - } - return nil -} - -// VerifyResult verifies that the given result returned from Reconcile is the -// result expected by the test case. -func (tc *TestCase) VerifyResult(result reconcile.Result) error { - if diff := cmp.Diff(tc.WantResult, result); diff != "" { - return fmt.Errorf("unexpected reconcile Result (-want +got) %v", diff) - } - return nil -} - -// VerifyResult verifies that the given result returned from Reconcile is the -// result expected by the test case. -func (tc *TestCase) VerifyResultSDK(result runtime.Object) error { - if diff := cmp.Diff(tc.WantResultObject, result); diff != "" { - return fmt.Errorf("unexpected reconcile Result Object (-want +got) %v", diff) - } - return nil -} - -type stateErrors struct { - errors []error -} - -func (se stateErrors) Error() string { - msgs := make([]string, 0) - for _, err := range se.errors { - msgs = append(msgs, err.Error()) - } - return strings.Join(msgs, "\n") -} - -// VerifyWantPresent verifies that the client contains all the objects expected -// to be present after reconciliation. -func (tc *TestCase) VerifyWantPresent(c client.Client) error { - var errs stateErrors - for _, wp := range tc.WantPresent { - o, err := scheme.Scheme.New(wp.GetObjectKind().GroupVersionKind()) - if err != nil { - errs.errors = append(errs.errors, fmt.Errorf("error creating a copy of %T: %v", wp, err)) - } - acc, err := meta.Accessor(wp) - if err != nil { - errs.errors = append(errs.errors, fmt.Errorf("error getting accessor for %#v %v", wp, err)) - } - err = c.Get(context.TODO(), client.ObjectKey{Namespace: acc.GetNamespace(), Name: acc.GetName()}, o) - if err != nil { - if apierrors.IsNotFound(err) { - errs.errors = append(errs.errors, fmt.Errorf("want present %T %s/%s, got absent", wp, acc.GetNamespace(), acc.GetName())) - } else { - errs.errors = append(errs.errors, fmt.Errorf("error getting %T %s/%s: %v", wp, acc.GetNamespace(), acc.GetName(), err)) - } - } - - diffOpts := cmp.Options{ - // Ignore TypeMeta, since the objects created by the controller won't have - // it - cmpopts.IgnoreTypes(metav1.TypeMeta{}), - } - - if tc.IgnoreTimes { - // Ignore VolatileTime fields, since they rarely compare correctly. - diffOpts = append(diffOpts, cmpopts.IgnoreTypes(apis.VolatileTime{})) - } - - if diff := cmp.Diff(wp, o, diffOpts...); diff != "" { - errs.errors = append(errs.errors, fmt.Errorf("Unexpected present %T %s/%s (-want +got):\n%v", wp, acc.GetNamespace(), acc.GetName(), diff)) - } - } - if len(errs.errors) > 0 { - return errs - } - return nil -} - -// VerifyWantAbsent verifies that the client does not contain any of the objects -// expected to be absent after reconciliation. -func (tc *TestCase) VerifyWantAbsent(c client.Client) error { - var errs stateErrors - for _, wa := range tc.WantAbsent { - acc, err := meta.Accessor(wa) - if err != nil { - errs.errors = append(errs.errors, fmt.Errorf("error getting accessor for %#v %v", wa, err)) - } - err = c.Get(context.TODO(), client.ObjectKey{Namespace: acc.GetNamespace(), Name: acc.GetName()}, wa) - if err == nil { - errs.errors = append(errs.errors, fmt.Errorf("want absent, got present %T %s/%s", wa, acc.GetNamespace(), acc.GetName())) - } - if !apierrors.IsNotFound(err) { - errs.errors = append(errs.errors, fmt.Errorf("error getting %T %s/%s: %v", wa, acc.GetNamespace(), acc.GetName(), err)) - } - } - if len(errs.errors) > 0 { - return errs - } - return nil -} diff --git a/vendor/github.com/knative/eventing-sources/pkg/kncloudevents/good_client.go b/vendor/github.com/knative/eventing-sources/pkg/kncloudevents/good_client.go deleted file mode 100644 index 52384cc889e..00000000000 --- a/vendor/github.com/knative/eventing-sources/pkg/kncloudevents/good_client.go +++ /dev/null @@ -1,28 +0,0 @@ -package kncloudevents - -import ( - "github.com/cloudevents/sdk-go/pkg/cloudevents/client" - "github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http" -) - -func NewDefaultClient(target ...string) (client.Client, error) { - tOpts := []http.Option{http.WithBinaryEncoding()} - if len(target) > 0 && target[0] != "" { - tOpts = append(tOpts, http.WithTarget(target[0])) - } - - // Make an http transport for the CloudEvents client. - t, err := http.New(tOpts...) - if err != nil { - return nil, err - } - // Use the transport to make a new CloudEvents client. - c, err := client.New(t, - client.WithUUIDs(), - client.WithTimeNow(), - ) - if err != nil { - return nil, err - } - return c, nil -} diff --git a/vendor/github.com/knative/eventing-sources/test/test_images/k8sevents/kodata/LICENSE b/vendor/github.com/knative/eventing-sources/test/test_images/k8sevents/kodata/LICENSE deleted file mode 120000 index 14776154326..00000000000 --- a/vendor/github.com/knative/eventing-sources/test/test_images/k8sevents/kodata/LICENSE +++ /dev/null @@ -1 +0,0 @@ -../../../../LICENSE \ No newline at end of file diff --git a/vendor/github.com/knative/eventing-sources/test/test_images/k8sevents/kodata/VENDOR-LICENSE b/vendor/github.com/knative/eventing-sources/test/test_images/k8sevents/kodata/VENDOR-LICENSE deleted file mode 120000 index 7322c09d957..00000000000 --- a/vendor/github.com/knative/eventing-sources/test/test_images/k8sevents/kodata/VENDOR-LICENSE +++ /dev/null @@ -1 +0,0 @@ -../../../../third_party/VENDOR-LICENSE \ No newline at end of file From 3ed1763899de30119ea374918357f6f6818c4686 Mon Sep 17 00:00:00 2001 From: Scott Nichols Date: Wed, 24 Apr 2019 09:22:56 -0700 Subject: [PATCH 09/25] update codegen. --- pkg/apis/eventing/v1alpha1/doc.go | 5 +- pkg/apis/sources/v1alpha1/cron_job_types.go | 7 +- .../sources/v1alpha1/zz_generated.deepcopy.go | 117 ------------------ .../typed/sources/v1alpha1/cronjobsource.go | 2 +- .../v1alpha1/fake/fake_cronjobsource.go | 2 +- .../v1alpha1/fake/fake_sources_client.go | 5 + .../sources/v1alpha1/generated_expansion.go | 2 + .../typed/sources/v1alpha1/sources_client.go | 5 + .../informers/externalversions/factory.go | 6 + .../informers/externalversions/generic.go | 5 + .../externalversions/sources/interface.go | 2 +- .../sources/v1alpha1/cronjobsource.go | 2 +- .../sources/v1alpha1/interface.go | 2 +- .../listers/sources/v1alpha1/cronjobsource.go | 2 +- .../sources/v1alpha1/expansion_generated.go | 2 +- 15 files changed, 38 insertions(+), 128 deletions(-) delete mode 100644 pkg/apis/sources/v1alpha1/zz_generated.deepcopy.go diff --git a/pkg/apis/eventing/v1alpha1/doc.go b/pkg/apis/eventing/v1alpha1/doc.go index e080fe737d2..1b017951a8a 100644 --- a/pkg/apis/eventing/v1alpha1/doc.go +++ b/pkg/apis/eventing/v1alpha1/doc.go @@ -1,9 +1,12 @@ /* -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. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. diff --git a/pkg/apis/sources/v1alpha1/cron_job_types.go b/pkg/apis/sources/v1alpha1/cron_job_types.go index 1bfb7957355..439184aba9d 100644 --- a/pkg/apis/sources/v1alpha1/cron_job_types.go +++ b/pkg/apis/sources/v1alpha1/cron_job_types.go @@ -28,8 +28,7 @@ import ( // +genclient // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -// TODO: We should add defaults and validation. +// +k8s:defaulter-gen=true // CronJobSource is the Schema for the cronjobsources API. type CronJobSource struct { @@ -40,7 +39,9 @@ type CronJobSource struct { Status CronJobSourceStatus `json:"status,omitempty"` } -// Check that CronJobSource can be validated and can be defaulted. +// TODO: Check that CronJobSource can be validated and can be defaulted. + +// Check that it is a runtime object. var _ runtime.Object = (*CronJobSource)(nil) // Check that we can create OwnerReferences to a Configuration. diff --git a/pkg/apis/sources/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/sources/v1alpha1/zz_generated.deepcopy.go deleted file mode 100644 index a6d2202a0ff..00000000000 --- a/pkg/apis/sources/v1alpha1/zz_generated.deepcopy.go +++ /dev/null @@ -1,117 +0,0 @@ -// +build !ignore_autogenerated - -/* -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. -*/ - -// Code generated by deepcopy-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - v1 "k8s.io/api/core/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 *CronJobSource) DeepCopyInto(out *CronJobSource) { - *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 CronJobSource. -func (in *CronJobSource) DeepCopy() *CronJobSource { - if in == nil { - return nil - } - out := new(CronJobSource) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *CronJobSourceList) DeepCopyInto(out *CronJobSourceList) { - *out = *in - out.TypeMeta = in.TypeMeta - out.ListMeta = in.ListMeta - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]CronJobSource, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CronJobSourceList. -func (in *CronJobSourceList) DeepCopy() *CronJobSourceList { - if in == nil { - return nil - } - out := new(CronJobSourceList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *CronJobSourceList) 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 *CronJobSourceSpec) DeepCopyInto(out *CronJobSourceSpec) { - *out = *in - if in.Sink != nil { - in, out := &in.Sink, &out.Sink - *out = new(v1.ObjectReference) - **out = **in - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CronJobSourceSpec. -func (in *CronJobSourceSpec) DeepCopy() *CronJobSourceSpec { - if in == nil { - return nil - } - out := new(CronJobSourceSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *CronJobSourceStatus) DeepCopyInto(out *CronJobSourceStatus) { - *out = *in - in.Status.DeepCopyInto(&out.Status) - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CronJobSourceStatus. -func (in *CronJobSourceStatus) DeepCopy() *CronJobSourceStatus { - if in == nil { - return nil - } - out := new(CronJobSourceStatus) - in.DeepCopyInto(out) - return out -} diff --git a/pkg/client/clientset/versioned/typed/sources/v1alpha1/cronjobsource.go b/pkg/client/clientset/versioned/typed/sources/v1alpha1/cronjobsource.go index f18f9c8150b..bb6a1257c6f 100644 --- a/pkg/client/clientset/versioned/typed/sources/v1alpha1/cronjobsource.go +++ b/pkg/client/clientset/versioned/typed/sources/v1alpha1/cronjobsource.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/client/clientset/versioned/typed/sources/v1alpha1/fake/fake_cronjobsource.go b/pkg/client/clientset/versioned/typed/sources/v1alpha1/fake/fake_cronjobsource.go index f90c9761f1c..a7b30f81401 100644 --- a/pkg/client/clientset/versioned/typed/sources/v1alpha1/fake/fake_cronjobsource.go +++ b/pkg/client/clientset/versioned/typed/sources/v1alpha1/fake/fake_cronjobsource.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/client/clientset/versioned/typed/sources/v1alpha1/fake/fake_sources_client.go b/pkg/client/clientset/versioned/typed/sources/v1alpha1/fake/fake_sources_client.go index 5fbb3e91bcb..c2d9faeb94a 100644 --- a/pkg/client/clientset/versioned/typed/sources/v1alpha1/fake/fake_sources_client.go +++ b/pkg/client/clientset/versioned/typed/sources/v1alpha1/fake/fake_sources_client.go @@ -19,6 +19,7 @@ limitations under the License. package fake import ( + v1alpha1 "github.com/knative/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha1" rest "k8s.io/client-go/rest" testing "k8s.io/client-go/testing" ) @@ -27,6 +28,10 @@ type FakeSourcesV1alpha1 struct { *testing.Fake } +func (c *FakeSourcesV1alpha1) CronJobSources(namespace string) v1alpha1.CronJobSourceInterface { + return &FakeCronJobSources{c, namespace} +} + // RESTClient returns a RESTClient that is used to communicate // with API server by this client implementation. func (c *FakeSourcesV1alpha1) RESTClient() rest.Interface { diff --git a/pkg/client/clientset/versioned/typed/sources/v1alpha1/generated_expansion.go b/pkg/client/clientset/versioned/typed/sources/v1alpha1/generated_expansion.go index 3d57ca700bf..e3e7bf27492 100644 --- a/pkg/client/clientset/versioned/typed/sources/v1alpha1/generated_expansion.go +++ b/pkg/client/clientset/versioned/typed/sources/v1alpha1/generated_expansion.go @@ -17,3 +17,5 @@ limitations under the License. // Code generated by client-gen. DO NOT EDIT. package v1alpha1 + +type CronJobSourceExpansion interface{} diff --git a/pkg/client/clientset/versioned/typed/sources/v1alpha1/sources_client.go b/pkg/client/clientset/versioned/typed/sources/v1alpha1/sources_client.go index edbeb24bcdb..31733ad3ea4 100644 --- a/pkg/client/clientset/versioned/typed/sources/v1alpha1/sources_client.go +++ b/pkg/client/clientset/versioned/typed/sources/v1alpha1/sources_client.go @@ -27,6 +27,7 @@ import ( type SourcesV1alpha1Interface interface { RESTClient() rest.Interface + CronJobSourcesGetter } // SourcesV1alpha1Client is used to interact with features provided by the sources.eventing.knative.dev group. @@ -34,6 +35,10 @@ type SourcesV1alpha1Client struct { restClient rest.Interface } +func (c *SourcesV1alpha1Client) CronJobSources(namespace string) CronJobSourceInterface { + return newCronJobSources(c, namespace) +} + // NewForConfig creates a new SourcesV1alpha1Client for the given config. func NewForConfig(c *rest.Config) (*SourcesV1alpha1Client, error) { config := *c diff --git a/pkg/client/informers/externalversions/factory.go b/pkg/client/informers/externalversions/factory.go index f5f0897b7c9..c591485735a 100644 --- a/pkg/client/informers/externalversions/factory.go +++ b/pkg/client/informers/externalversions/factory.go @@ -26,6 +26,7 @@ import ( versioned "github.com/knative/eventing/pkg/client/clientset/versioned" eventing "github.com/knative/eventing/pkg/client/informers/externalversions/eventing" internalinterfaces "github.com/knative/eventing/pkg/client/informers/externalversions/internalinterfaces" + sources "github.com/knative/eventing/pkg/client/informers/externalversions/sources" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" schema "k8s.io/apimachinery/pkg/runtime/schema" @@ -173,8 +174,13 @@ type SharedInformerFactory interface { WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool Eventing() eventing.Interface + Sources() sources.Interface } func (f *sharedInformerFactory) Eventing() eventing.Interface { return eventing.New(f, f.namespace, f.tweakListOptions) } + +func (f *sharedInformerFactory) Sources() sources.Interface { + return sources.New(f, f.namespace, f.tweakListOptions) +} diff --git a/pkg/client/informers/externalversions/generic.go b/pkg/client/informers/externalversions/generic.go index 8aa9b1ad555..013b0b1e9fc 100644 --- a/pkg/client/informers/externalversions/generic.go +++ b/pkg/client/informers/externalversions/generic.go @@ -22,6 +22,7 @@ import ( "fmt" v1alpha1 "github.com/knative/eventing/pkg/apis/eventing/v1alpha1" + sourcesv1alpha1 "github.com/knative/eventing/pkg/apis/sources/v1alpha1" schema "k8s.io/apimachinery/pkg/runtime/schema" cache "k8s.io/client-go/tools/cache" ) @@ -64,6 +65,10 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource case v1alpha1.SchemeGroupVersion.WithResource("triggers"): return &genericInformer{resource: resource.GroupResource(), informer: f.Eventing().V1alpha1().Triggers().Informer()}, nil + // Group=sources.eventing.knative.dev, Version=v1alpha1 + case sourcesv1alpha1.SchemeGroupVersion.WithResource("cronjobsources"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Sources().V1alpha1().CronJobSources().Informer()}, nil + } return nil, fmt.Errorf("no informer found for %v", resource) diff --git a/pkg/client/informers/externalversions/sources/interface.go b/pkg/client/informers/externalversions/sources/interface.go index 654f1938531..d638f2a8578 100644 --- a/pkg/client/informers/externalversions/sources/interface.go +++ b/pkg/client/informers/externalversions/sources/interface.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/client/informers/externalversions/sources/v1alpha1/cronjobsource.go b/pkg/client/informers/externalversions/sources/v1alpha1/cronjobsource.go index c05b7692e5a..c6d831f8ecc 100644 --- a/pkg/client/informers/externalversions/sources/v1alpha1/cronjobsource.go +++ b/pkg/client/informers/externalversions/sources/v1alpha1/cronjobsource.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/client/informers/externalversions/sources/v1alpha1/interface.go b/pkg/client/informers/externalversions/sources/v1alpha1/interface.go index cf621f01e7e..244340025a8 100644 --- a/pkg/client/informers/externalversions/sources/v1alpha1/interface.go +++ b/pkg/client/informers/externalversions/sources/v1alpha1/interface.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/client/listers/sources/v1alpha1/cronjobsource.go b/pkg/client/listers/sources/v1alpha1/cronjobsource.go index 4c4d43bcfac..a720fb0e9df 100644 --- a/pkg/client/listers/sources/v1alpha1/cronjobsource.go +++ b/pkg/client/listers/sources/v1alpha1/cronjobsource.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/client/listers/sources/v1alpha1/expansion_generated.go b/pkg/client/listers/sources/v1alpha1/expansion_generated.go index f9b1368c856..444c53f7032 100644 --- a/pkg/client/listers/sources/v1alpha1/expansion_generated.go +++ b/pkg/client/listers/sources/v1alpha1/expansion_generated.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. From 33d31c02ce5a1a7209ad319ef5973a3976211cd2 Mon Sep 17 00:00:00 2001 From: Scott Nichols Date: Wed, 24 Apr 2019 09:51:06 -0700 Subject: [PATCH 10/25] add deepcopy. --- .../sources/v1alpha1/zz_generated.deepcopy.go | 125 ++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 pkg/apis/sources/v1alpha1/zz_generated.deepcopy.go diff --git a/pkg/apis/sources/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/sources/v1alpha1/zz_generated.deepcopy.go new file mode 100644 index 00000000000..686c603a5e3 --- /dev/null +++ b/pkg/apis/sources/v1alpha1/zz_generated.deepcopy.go @@ -0,0 +1,125 @@ +// +build !ignore_autogenerated + +/* +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. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + v1 "k8s.io/api/core/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 *CronJobSource) DeepCopyInto(out *CronJobSource) { + *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 CronJobSource. +func (in *CronJobSource) DeepCopy() *CronJobSource { + if in == nil { + return nil + } + out := new(CronJobSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *CronJobSource) 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 *CronJobSourceList) DeepCopyInto(out *CronJobSourceList) { + *out = *in + out.TypeMeta = in.TypeMeta + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]CronJobSource, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CronJobSourceList. +func (in *CronJobSourceList) DeepCopy() *CronJobSourceList { + if in == nil { + return nil + } + out := new(CronJobSourceList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *CronJobSourceList) 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 *CronJobSourceSpec) DeepCopyInto(out *CronJobSourceSpec) { + *out = *in + if in.Sink != nil { + in, out := &in.Sink, &out.Sink + *out = new(v1.ObjectReference) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CronJobSourceSpec. +func (in *CronJobSourceSpec) DeepCopy() *CronJobSourceSpec { + if in == nil { + return nil + } + out := new(CronJobSourceSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CronJobSourceStatus) DeepCopyInto(out *CronJobSourceStatus) { + *out = *in + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CronJobSourceStatus. +func (in *CronJobSourceStatus) DeepCopy() *CronJobSourceStatus { + if in == nil { + return nil + } + out := new(CronJobSourceStatus) + in.DeepCopyInto(out) + return out +} From 5f18e08ce8305d691bb7d8ea7c9e329d4340c53b Mon Sep 17 00:00:00 2001 From: Scott Nichols Date: Wed, 24 Apr 2019 10:30:19 -0700 Subject: [PATCH 11/25] clean copyright. --- pkg/apis/sources/v1alpha1/cron_job_lifecycle_test.go | 4 ---- pkg/apis/sources/v1alpha1/register_test.go | 8 ++++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/pkg/apis/sources/v1alpha1/cron_job_lifecycle_test.go b/pkg/apis/sources/v1alpha1/cron_job_lifecycle_test.go index c6585c1703b..9dd7aaefb88 100644 --- a/pkg/apis/sources/v1alpha1/cron_job_lifecycle_test.go +++ b/pkg/apis/sources/v1alpha1/cron_job_lifecycle_test.go @@ -1,9 +1,5 @@ /* -<<<<<<< HEAD -Copyright 2018 The Knative Authors -======= Copyright 2019 The Knative Authors ->>>>>>> cronjobsource 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/sources/v1alpha1/register_test.go b/pkg/apis/sources/v1alpha1/register_test.go index 4925698f024..2c4e17d8b5e 100644 --- a/pkg/apis/sources/v1alpha1/register_test.go +++ b/pkg/apis/sources/v1alpha1/register_test.go @@ -1,19 +1,19 @@ /* -<<<<<<< HEAD -Copyright 2018 The Knative Authors -======= Copyright 2019 The Knative Authors ->>>>>>> cronjobsource + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 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 ( From aa1dc8b0b99c6b382d03bb2635522908a41ded4d Mon Sep 17 00:00:00 2001 From: Scott Nichols Date: Wed, 24 Apr 2019 13:22:33 -0700 Subject: [PATCH 12/25] updating to have a source controller. --- Gopkg.lock | 9 +- cmd/controller/main.go | 12 +- cmd/source-controller/kodata/HEAD | 1 + cmd/source-controller/kodata/LICENSE | 1 + cmd/source-controller/kodata/VENDOR-LICENSE | 1 + cmd/source-controller/main.go | 163 +++++++++++++ config/400-source-controller-service.yaml | 30 +++ config/500-source-controller.yaml | 66 ++++++ pkg/logconfig/config.go | 3 + .../golang.org/x/oauth2/google/appengine.go | 89 ++----- .../x/oauth2/google/appengine_gen1.go | 77 ++++++ .../x/oauth2/google/appengine_gen2_flex.go | 27 +++ .../x/oauth2/google/appengine_hook.go | 14 -- .../x/oauth2/google/appengineflex_hook.go | 11 - vendor/golang.org/x/oauth2/google/default.go | 57 ++++- .../x/oauth2/google/{doc_go19.go => doc.go} | 2 - .../x/oauth2/google/doc_not_go19.go | 43 ---- vendor/golang.org/x/oauth2/google/go19.go | 57 ----- vendor/golang.org/x/oauth2/google/google.go | 24 +- vendor/golang.org/x/oauth2/google/not_go19.go | 54 ----- vendor/golang.org/x/oauth2/google/sdk.go | 2 +- vendor/golang.org/x/oauth2/internal/oauth2.go | 2 +- vendor/golang.org/x/oauth2/internal/token.go | 220 ++++++++++-------- .../golang.org/x/oauth2/internal/transport.go | 3 +- vendor/golang.org/x/oauth2/jwt/jwt.go | 10 +- vendor/golang.org/x/oauth2/oauth2.go | 66 ++++-- vendor/golang.org/x/oauth2/token.go | 9 +- vendor/golang.org/x/oauth2/transport.go | 16 +- .../pkg/runtime/scheme/scheme.go | 56 ----- 29 files changed, 661 insertions(+), 464 deletions(-) create mode 120000 cmd/source-controller/kodata/HEAD create mode 120000 cmd/source-controller/kodata/LICENSE create mode 120000 cmd/source-controller/kodata/VENDOR-LICENSE create mode 100644 cmd/source-controller/main.go create mode 100644 config/400-source-controller-service.yaml create mode 100644 config/500-source-controller.yaml 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 delete mode 100644 vendor/golang.org/x/oauth2/google/appengine_hook.go delete mode 100644 vendor/golang.org/x/oauth2/google/appengineflex_hook.go rename vendor/golang.org/x/oauth2/google/{doc_go19.go => doc.go} (99%) delete mode 100644 vendor/golang.org/x/oauth2/google/doc_not_go19.go delete mode 100644 vendor/golang.org/x/oauth2/google/go19.go delete mode 100644 vendor/golang.org/x/oauth2/google/not_go19.go delete mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/runtime/scheme/scheme.go diff --git a/Gopkg.lock b/Gopkg.lock index 78115757a79..a3e5d5fbee2 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -788,7 +788,8 @@ revision = "1e491301e022f8f977054da4c2d852decd59571f" [[projects]] - digest = "1:46bd4e66bfce5e77f08fc2e8dcacc3676e679241ce83d9c150ff0397d686dd44" + branch = "master" + digest = "1:3121d742fbe48670a16d98b6da4693501fc33cd76d69ed6f35850c564f255c65" name = "golang.org/x/oauth2" packages = [ ".", @@ -798,7 +799,7 @@ "jwt", ] pruneopts = "NUT" - revision = "cdc340f7c179dbbfa4afd43b7614e8fcadde4269" + revision = "9f3314589c9a9136388751d9adae6b0ed400978a" [[projects]] branch = "master" @@ -1322,7 +1323,7 @@ revision = "8a9b82f00b3a86eac24681da3f9fe6c34c01cea2" [[projects]] - digest = "1:b96e8e4a7931b07c33fdb206bfc4d27273bd599e48061500138ed69303388140" + digest = "1:a8495647d9f03401c36b801a0644207a434f76ed9d4fc4ea80c46700f0ccc575" name = "sigs.k8s.io/controller-runtime" packages = [ "pkg/cache", @@ -1346,7 +1347,6 @@ "pkg/recorder", "pkg/runtime/inject", "pkg/runtime/log", - "pkg/runtime/scheme", "pkg/runtime/signals", "pkg/source", "pkg/source/internal", @@ -1453,6 +1453,7 @@ "k8s.io/client-go/rest", "k8s.io/client-go/testing", "k8s.io/client-go/tools/cache", + "k8s.io/client-go/tools/clientcmd", "k8s.io/client-go/tools/record", "k8s.io/client-go/util/flowcontrol", "k8s.io/client-go/util/workqueue", diff --git a/cmd/controller/main.go b/cmd/controller/main.go index 01083e9f5a7..6d0096c1e3a 100644 --- a/cmd/controller/main.go +++ b/cmd/controller/main.go @@ -19,7 +19,6 @@ package main import ( "context" "flag" - "github.com/knative/eventing/pkg/reconciler/cronjobsource" "log" "net/http" "os" @@ -97,7 +96,7 @@ func startPkgController(stopCh <-chan struct{}, cfg *rest.Config, logger *zap.Su logger = logger.With(zap.String("controller/impl", "pkg")) logger.Info("Starting the controller") - const numControllers = 5 + const numControllers = 4 cfg.QPS = numControllers * rest.DefaultQPS cfg.Burst = numControllers * rest.DefaultBurst opt := reconciler.NewOptionsOrDie(cfg, logger, stopCh) @@ -110,11 +109,9 @@ func startPkgController(stopCh <-chan struct{}, cfg *rest.Config, logger *zap.Su channelInformer := eventingInformerFactory.Eventing().V1alpha1().Channels() subscriptionInformer := eventingInformerFactory.Eventing().V1alpha1().Subscriptions() brokerInformer := eventingInformerFactory.Eventing().V1alpha1().Brokers() - cronjobsourceInformer := eventingInformerFactory.Sources().V1alpha1().CronJobSources() // Kube coreServiceInformer := kubeInformerFactory.Core().V1().Services() - deploymentInformer := kubeInformerFactory.Apps().V1().Deployments() coreNamespaceInformer := kubeInformerFactory.Core().V1().Namespaces() configMapInformer := kubeInformerFactory.Core().V1().ConfigMaps() @@ -142,11 +139,6 @@ func startPkgController(stopCh <-chan struct{}, cfg *rest.Config, logger *zap.Su brokerInformer, coreServiceInformer, ), - cronjobsource.NewController( - opt, - cronjobsourceInformer, - deploymentInformer, - ), } if len(controllers) != numControllers { logger.Fatalf("Number of controllers and QPS settings mismatch: %d != %d", len(controllers), numControllers) @@ -167,13 +159,11 @@ func startPkgController(stopCh <-chan struct{}, cfg *rest.Config, logger *zap.Su // Eventing brokerInformer.Informer(), channelInformer.Informer(), - cronjobsourceInformer.Informer(), subscriptionInformer.Informer(), triggerInformer.Informer(), // Kube configMapInformer.Informer(), coreServiceInformer.Informer(), - deploymentInformer.Informer(), coreNamespaceInformer.Informer(), ); err != nil { logger.Fatalf("Failed to start informers: %v", err) diff --git a/cmd/source-controller/kodata/HEAD b/cmd/source-controller/kodata/HEAD new file mode 120000 index 00000000000..8f63681d362 --- /dev/null +++ b/cmd/source-controller/kodata/HEAD @@ -0,0 +1 @@ +../../../.git/HEAD \ No newline at end of file diff --git a/cmd/source-controller/kodata/LICENSE b/cmd/source-controller/kodata/LICENSE new file mode 120000 index 00000000000..5853aaea53b --- /dev/null +++ b/cmd/source-controller/kodata/LICENSE @@ -0,0 +1 @@ +../../../LICENSE \ No newline at end of file diff --git a/cmd/source-controller/kodata/VENDOR-LICENSE b/cmd/source-controller/kodata/VENDOR-LICENSE new file mode 120000 index 00000000000..3cc89764519 --- /dev/null +++ b/cmd/source-controller/kodata/VENDOR-LICENSE @@ -0,0 +1 @@ +../../../third_party/VENDOR-LICENSE \ No newline at end of file diff --git a/cmd/source-controller/main.go b/cmd/source-controller/main.go new file mode 100644 index 00000000000..850b9049e5f --- /dev/null +++ b/cmd/source-controller/main.go @@ -0,0 +1,163 @@ +/* +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" + "k8s.io/client-go/tools/clientcmd" + "log" + + // Uncomment the following line to load the gcp plugin (only required to authenticate against GKE clusters). + _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" + + kubeinformers "k8s.io/client-go/informers" + "k8s.io/client-go/rest" + + informers "github.com/knative/eventing/pkg/client/informers/externalversions" + "github.com/knative/eventing/pkg/logconfig" + "github.com/knative/eventing/pkg/logging" + "github.com/knative/eventing/pkg/reconciler" + "github.com/knative/eventing/pkg/reconciler/cronjobsource" + "github.com/knative/pkg/configmap" + kncontroller "github.com/knative/pkg/controller" + "github.com/knative/pkg/logging/logkey" + "github.com/knative/pkg/signals" + "go.uber.org/zap" +) + +var ( + hardcodedLoggingConfig = flag.Bool("hardCodedLoggingConfig", false, "If true, use the hard coded logging config. It is intended to be used only when debugging outside a Kubernetes cluster.") + masterURL = flag.String("master", "", "The address of the Kubernetes API server. Overrides any value in kubeconfig. Only required if out-of-cluster.") + kubeconfig = flag.String("kubeconfig", "", "Path to a kubeconfig. Only required if out-of-cluster.") +) + +func main() { + flag.Parse() + + logger, atomicLevel := setupLogger() + defer logger.Sync() + logger = logger.With(zap.String(logkey.ControllerType, logconfig.SourceController)) + + // set up signals so we handle the first shutdown signal gracefully + stopCh := signals.SetupSignalHandler() + + cfg, err := clientcmd.BuildConfigFromFlags(*masterURL, *kubeconfig) + if err != nil { + logger.Fatalw("Error building kubeconfig", zap.Error(err)) + } + + logger = logger.With(zap.String("controller/impl", "pkg")) + logger.Info("Starting the controller") + + const numControllers = 1 + cfg.QPS = numControllers * rest.DefaultQPS + cfg.Burst = numControllers * rest.DefaultBurst + opt := reconciler.NewOptionsOrDie(cfg, logger, stopCh) + + kubeInformerFactory := kubeinformers.NewSharedInformerFactory(opt.KubeClientSet, opt.ResyncPeriod) + eventingInformerFactory := informers.NewSharedInformerFactory(opt.EventingClientSet, opt.ResyncPeriod) + + // Eventing + cronjobsourceInformer := eventingInformerFactory.Sources().V1alpha1().CronJobSources() + + // Kube + deploymentInformer := kubeInformerFactory.Apps().V1().Deployments() + + // Build all of our controllers, with the clients constructed above. + // Add new controllers to this array. + // You also need to modify numControllers above to match this. + controllers := []*kncontroller.Impl{ + cronjobsource.NewController( + opt, + cronjobsourceInformer, + deploymentInformer, + ), + } + if len(controllers) != numControllers { + logger.Fatalf("Number of controllers and QPS settings mismatch: %d != %d", len(controllers), numControllers) + } + + // Watch the logging config map and dynamically update logging levels. + opt.ConfigMapWatcher.Watch(logconfig.ConfigMapName(), logging.UpdateLevelFromConfigMap(logger, atomicLevel, logconfig.SourceController)) + // TODO: Watch the observability config map and dynamically update metrics exporter. + //opt.ConfigMapWatcher.Watch(metrics.ObservabilityConfigName, metrics.UpdateExporterFromConfigMap(component, logger)) + if err := opt.ConfigMapWatcher.Start(stopCh); err != nil { + logger.Fatalw("failed to start configuration manager", zap.Error(err)) + } + + // Start all of the informers and wait for them to sync. + logger.Info("Starting informers.") + if err := kncontroller.StartInformers( + stopCh, + // Eventing + cronjobsourceInformer.Informer(), + // Kube + deploymentInformer.Informer(), + ); err != nil { + logger.Fatalf("Failed to start informers: %v", err) + } + + // Start all of the controllers. + logger.Info("Starting controllers.") + go kncontroller.StartAll(stopCh, controllers...) + + <-stopCh +} + +func setupLogger() (*zap.SugaredLogger, zap.AtomicLevel) { + // Set up our logger. + loggingConfigMap := getLoggingConfigOrDie() + loggingConfig, err := logging.NewConfigFromMap(loggingConfigMap) + if err != nil { + log.Fatalf("Error parsing logging configuration: %v", err) + } + return logging.NewLoggerFromConfig(loggingConfig, logconfig.Controller) +} + +func getLoggingConfigOrDie() map[string]string { + if hardcodedLoggingConfig != nil && *hardcodedLoggingConfig { + return map[string]string{ + "loglevel.controller": "info", + "zap-logger-config": ` + { + "level": "info", + "development": false, + "outputPaths": ["stdout"], + "errorOutputPaths": ["stderr"], + "encoding": "json", + "encoderConfig": { + "timeKey": "ts", + "levelKey": "level", + "nameKey": "logger", + "callerKey": "caller", + "messageKey": "msg", + "stacktraceKey": "stacktrace", + "lineEnding": "", + "levelEncoder": "", + "timeEncoder": "iso8601", + "durationEncoder": "", + "callerEncoder": "" + }`, + } + } else { + cm, err := configmap.Load("/etc/config-logging") + if err != nil { + log.Fatalf("Error loading logging configuration: %v", err) + } + return cm + } +} diff --git a/config/400-source-controller-service.yaml b/config/400-source-controller-service.yaml new file mode 100644 index 00000000000..d1a8038385c --- /dev/null +++ b/config/400-source-controller-service.yaml @@ -0,0 +1,30 @@ +# 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 +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT 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: v1 +kind: Service +metadata: + labels: + app: source-controller + serving.knative.dev/release: devel + name: source-controller + namespace: knative-eventing +spec: + ports: + - name: metrics + port: 9090 + protocol: TCP + targetPort: 9090 + selector: + app: source-controller \ No newline at end of file diff --git a/config/500-source-controller.yaml b/config/500-source-controller.yaml new file mode 100644 index 00000000000..fdf2bbbeaab --- /dev/null +++ b/config/500-source-controller.yaml @@ -0,0 +1,66 @@ +# 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: apps/v1 +kind: Deployment +metadata: + name: controller + namespace: knative-eventing + labels: + eventing.knative.dev/release: devel +spec: + replicas: 1 + selector: + matchLabels: + app: source-controller + template: + metadata: + annotations: + sidecar.istio.io/inject: "false" + labels: + app: source-controller + eventing.knative.dev/release: devel + spec: + serviceAccountName: knative-controller + containers: + - name: controller + # This is the Go import path for the binary that is containerized + # and substituted here. + image: github.com/knative/eventing/cmd/source-controller + resources: + requests: + cpu: 100m + memory: 100Mi + limits: + cpu: 1000m + memory: 1000Mi + ports: + - name: metrics + containerPort: 9090 + volumeMounts: + - name: config-logging + mountPath: /etc/config-logging + env: + - name: SYSTEM_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: CONFIG_LOGGING_NAME + value: config-logging + - name: CRONJOB_RA_IMAGE + value: github.com/knative/eventing/cmd/cronjob_receive_adapter + volumes: + - name: config-logging + configMap: + name: config-logging diff --git a/pkg/logconfig/config.go b/pkg/logconfig/config.go index 9ef2e550781..9ae1c88da71 100644 --- a/pkg/logconfig/config.go +++ b/pkg/logconfig/config.go @@ -33,6 +33,9 @@ const ( // Controller is the name of the override key used inside of the logging config for Controller. Controller = "controller" + // SourceController is the name of the override key used inside of the logging config for Controller. + SourceController = "source-controller" + // Webhook is the name of the override key used inside of the logging config for Webhook Controller. WebhookNameEnv = "WEBHOOK_NAME" ) diff --git a/vendor/golang.org/x/oauth2/google/appengine.go b/vendor/golang.org/x/oauth2/google/appengine.go index 50d918b8788..feb1157b15b 100644 --- a/vendor/golang.org/x/oauth2/google/appengine.go +++ b/vendor/golang.org/x/oauth2/google/appengine.go @@ -5,85 +5,34 @@ package google import ( - "sort" - "strings" - "sync" + "context" "time" - "golang.org/x/net/context" "golang.org/x/oauth2" ) -// appengineFlex is set at init time by appengineflex_hook.go. If true, we are on App Engine Flex. -var appengineFlex bool - -// Set at init time by appengine_hook.go. If nil, we're not on App Engine. +// Set at init time by appengine_gen1.go. If nil, we're not on App Engine standard first generation (<= Go 1.9) or App Engine flexible. var appengineTokenFunc func(c context.Context, scopes ...string) (token string, expiry time.Time, err error) -// Set at init time by appengine_hook.go. If nil, we're not on App Engine. +// Set at init time by appengine_gen1.go. If nil, we're not on App Engine standard first generation (<= Go 1.9) or App Engine flexible. var appengineAppIDFunc func(c context.Context) string -// AppEngineTokenSource returns a token source that fetches tokens -// issued to the current App Engine application's service account. -// If you are implementing a 3-legged OAuth 2.0 flow on App Engine -// that involves user accounts, see oauth2.Config instead. +// AppEngineTokenSource returns a token source that fetches tokens from either +// the current application's service account or from the metadata server, +// depending on the App Engine environment. See below for environment-specific +// details. If you are implementing a 3-legged OAuth 2.0 flow on App Engine that +// involves user accounts, see oauth2.Config instead. +// +// First generation App Engine runtimes (<= Go 1.9): +// AppEngineTokenSource returns a token source that fetches tokens issued to the +// current App Engine application's service account. The provided context must have +// come from appengine.NewContext. // -// The provided context must have come from appengine.NewContext. +// Second generation App Engine runtimes (>= Go 1.11) and App Engine flexible: +// AppEngineTokenSource is DEPRECATED on second generation runtimes and on the +// flexible environment. It delegates to ComputeTokenSource, and the provided +// context and scopes are not used. Please use DefaultTokenSource (or ComputeTokenSource, +// which DefaultTokenSource will use in this case) instead. func AppEngineTokenSource(ctx context.Context, scope ...string) oauth2.TokenSource { - if appengineTokenFunc == nil { - panic("google: AppEngineTokenSource can only be used on App Engine.") - } - scopes := append([]string{}, scope...) - sort.Strings(scopes) - return &appEngineTokenSource{ - 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 appEngineTokenSource struct { - ctx context.Context - scopes []string - key string // to aeTokens map; space-separated scopes -} - -func (ts *appEngineTokenSource) Token() (*oauth2.Token, error) { - if appengineTokenFunc == nil { - panic("google: AppEngineTokenSource can only be used on App Engine.") - } - - 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 + return appEngineTokenSource(ctx, scope...) } 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/appengine_hook.go b/vendor/golang.org/x/oauth2/google/appengine_hook.go deleted file mode 100644 index 56669eaa98d..00000000000 --- a/vendor/golang.org/x/oauth2/google/appengine_hook.go +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2015 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 appenginevm - -package google - -import "google.golang.org/appengine" - -func init() { - appengineTokenFunc = appengine.AccessToken - appengineAppIDFunc = appengine.AppID -} diff --git a/vendor/golang.org/x/oauth2/google/appengineflex_hook.go b/vendor/golang.org/x/oauth2/google/appengineflex_hook.go deleted file mode 100644 index 5d0231af2dd..00000000000 --- a/vendor/golang.org/x/oauth2/google/appengineflex_hook.go +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright 2015 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 appenginevm - -package google - -func init() { - appengineFlex = true // Flex doesn't support appengine.AccessToken; depend on metadata server. -} diff --git a/vendor/golang.org/x/oauth2/google/default.go b/vendor/golang.org/x/oauth2/google/default.go index a31607437d3..ad2c09236c5 100644 --- a/vendor/golang.org/x/oauth2/google/default.go +++ b/vendor/golang.org/x/oauth2/google/default.go @@ -5,6 +5,7 @@ package google import ( + "context" "encoding/json" "fmt" "io/ioutil" @@ -14,10 +15,28 @@ import ( "runtime" "cloud.google.com/go/compute/metadata" - "golang.org/x/net/context" "golang.org/x/oauth2" ) +// Credentials holds Google credentials, including "Application Default Credentials". +// For more details, see: +// https://developers.google.com/accounts/docs/application-default-credentials +type Credentials struct { + ProjectID string // may be empty + TokenSource oauth2.TokenSource + + // JSON contains the raw bytes from a JSON credentials file. + // This field may be nil if authentication is provided by the + // environment and not with a credentials file, e.g. when code is + // running on Google Cloud Platform. + JSON []byte +} + +// DefaultCredentials is the old name of Credentials. +// +// Deprecated: use Credentials instead. +type DefaultCredentials = Credentials + // DefaultClient returns an HTTP Client that uses the // DefaultTokenSource to obtain authentication credentials. func DefaultClient(ctx context.Context, scope ...string) (*http.Client, error) { @@ -39,8 +58,22 @@ func DefaultTokenSource(ctx context.Context, scope ...string) (oauth2.TokenSourc return creds.TokenSource, nil } -// Common implementation for FindDefaultCredentials. -func findDefaultCredentials(ctx context.Context, scopes []string) (*DefaultCredentials, error) { +// FindDefaultCredentials searches for "Application Default Credentials". +// +// It looks for credentials in the following places, +// preferring the first location found: +// +// 1. A JSON file whose path is specified by the +// GOOGLE_APPLICATION_CREDENTIALS environment variable. +// 2. A JSON file in a location known to the gcloud command-line tool. +// On Windows, this is %APPDATA%/gcloud/application_default_credentials.json. +// On other systems, $HOME/.config/gcloud/application_default_credentials.json. +// 3. On Google App Engine standard first generation runtimes (<= Go 1.9) it uses +// the appengine.AccessToken function. +// 4. On Google Compute Engine, Google App Engine standard second generation runtimes +// (>= Go 1.11), and Google App Engine flexible environment, it fetches +// credentials from the metadata server. +func FindDefaultCredentials(ctx context.Context, scopes ...string) (*Credentials, error) { // First, try the environment variable. const envVar = "GOOGLE_APPLICATION_CREDENTIALS" if filename := os.Getenv(envVar); filename != "" { @@ -59,20 +92,23 @@ func findDefaultCredentials(ctx context.Context, scopes []string) (*DefaultCrede return nil, fmt.Errorf("google: error getting credentials using well-known file (%v): %v", filename, err) } - // Third, if we're on Google App Engine use those credentials. - if appengineTokenFunc != nil && !appengineFlex { + // Third, if we're on a Google App Engine standard first generation runtime (<= Go 1.9) + // use those credentials. App Engine standard second generation runtimes (>= Go 1.11) + // and App Engine flexible use ComputeTokenSource and the metadata server. + if appengineTokenFunc != nil { return &DefaultCredentials{ ProjectID: appengineAppIDFunc(ctx), TokenSource: AppEngineTokenSource(ctx, scopes...), }, nil } - // Fourth, if we're on Google Compute Engine use the metadata server. + // Fourth, if we're on Google Compute Engine, an App Engine standard second generation runtime, + // or App Engine flexible, use the metadata server. if metadata.OnGCE() { id, _ := metadata.ProjectID() return &DefaultCredentials{ ProjectID: id, - TokenSource: ComputeTokenSource(""), + TokenSource: ComputeTokenSource("", scopes...), }, nil } @@ -81,8 +117,11 @@ func findDefaultCredentials(ctx context.Context, scopes []string) (*DefaultCrede return nil, fmt.Errorf("google: could not find default credentials. See %v for more information.", url) } -// Common implementation for CredentialsFromJSON. -func credentialsFromJSON(ctx context.Context, jsonData []byte, scopes []string) (*DefaultCredentials, error) { +// CredentialsFromJSON obtains Google credentials from a JSON value. The JSON can +// represent either a Google Developers Console client_credentials.json file (as in +// ConfigFromJSON) or a Google Developers service account key file (as in +// JWTConfigFromJSON). +func CredentialsFromJSON(ctx context.Context, jsonData []byte, scopes ...string) (*Credentials, error) { var f credentialsFile if err := json.Unmarshal(jsonData, &f); err != nil { return nil, err diff --git a/vendor/golang.org/x/oauth2/google/doc_go19.go b/vendor/golang.org/x/oauth2/google/doc.go similarity index 99% rename from vendor/golang.org/x/oauth2/google/doc_go19.go rename to vendor/golang.org/x/oauth2/google/doc.go index 2a86325fe3b..73be629033d 100644 --- a/vendor/golang.org/x/oauth2/google/doc_go19.go +++ b/vendor/golang.org/x/oauth2/google/doc.go @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build go1.9 - // 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 diff --git a/vendor/golang.org/x/oauth2/google/doc_not_go19.go b/vendor/golang.org/x/oauth2/google/doc_not_go19.go deleted file mode 100644 index 5c3c6e14812..00000000000 --- a/vendor/golang.org/x/oauth2/google/doc_not_go19.go +++ /dev/null @@ -1,43 +0,0 @@ -// 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 !go1.9 - -// 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 DefaultCredentials type represents Google Application Default Credentials, as -// well as other forms of credential. -// -// 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 DefaultCredentials returned may -// not be "Application Default Credentials".) The TokenSource in the returned value -// is the same as the one obtained from the oauth2.Config returned from -// ConfigFromJSON or JWTConfigFromJSON, but the DefaultCredentials may contain -// additional information that is useful is some circumstances. -package google // import "golang.org/x/oauth2/google" diff --git a/vendor/golang.org/x/oauth2/google/go19.go b/vendor/golang.org/x/oauth2/google/go19.go deleted file mode 100644 index 4d0318b1e16..00000000000 --- a/vendor/golang.org/x/oauth2/google/go19.go +++ /dev/null @@ -1,57 +0,0 @@ -// 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 go1.9 - -package google - -import ( - "golang.org/x/net/context" - "golang.org/x/oauth2" -) - -// Credentials holds Google credentials, including "Application Default Credentials". -// For more details, see: -// https://developers.google.com/accounts/docs/application-default-credentials -type Credentials struct { - ProjectID string // may be empty - TokenSource oauth2.TokenSource - - // JSON contains the raw bytes from a JSON credentials file. - // This field may be nil if authentication is provided by the - // environment and not with a credentials file, e.g. when code is - // running on Google Cloud Platform. - JSON []byte -} - -// DefaultCredentials is the old name of Credentials. -// -// Deprecated: use Credentials instead. -type DefaultCredentials = Credentials - -// FindDefaultCredentials searches for "Application Default Credentials". -// -// It looks for credentials in the following places, -// preferring the first location found: -// -// 1. A JSON file whose path is specified by the -// GOOGLE_APPLICATION_CREDENTIALS environment variable. -// 2. A JSON file in a location known to the gcloud command-line tool. -// On Windows, this is %APPDATA%/gcloud/application_default_credentials.json. -// On other systems, $HOME/.config/gcloud/application_default_credentials.json. -// 3. On Google App Engine it uses the appengine.AccessToken function. -// 4. On Google Compute Engine and Google App Engine Managed VMs, it fetches -// credentials from the metadata server. -// (In this final case any provided scopes are ignored.) -func FindDefaultCredentials(ctx context.Context, scopes ...string) (*Credentials, error) { - return findDefaultCredentials(ctx, scopes) -} - -// CredentialsFromJSON obtains Google credentials from a JSON value. The JSON can -// represent either a Google Developers Console client_credentials.json file (as in -// ConfigFromJSON) or a Google Developers service account key file (as in -// JWTConfigFromJSON). -func CredentialsFromJSON(ctx context.Context, jsonData []byte, scopes ...string) (*Credentials, error) { - return credentialsFromJSON(ctx, jsonData, scopes) -} diff --git a/vendor/golang.org/x/oauth2/google/google.go b/vendor/golang.org/x/oauth2/google/google.go index f7481fbcc63..6eb2aa95f5b 100644 --- a/vendor/golang.org/x/oauth2/google/google.go +++ b/vendor/golang.org/x/oauth2/google/google.go @@ -5,26 +5,28 @@ package google import ( + "context" "encoding/json" "errors" "fmt" + "net/url" "strings" "time" "cloud.google.com/go/compute/metadata" - "golang.org/x/net/context" "golang.org/x/oauth2" "golang.org/x/oauth2/jwt" ) // Endpoint is Google's OAuth 2.0 endpoint. var Endpoint = oauth2.Endpoint{ - AuthURL: "https://accounts.google.com/o/oauth2/auth", - TokenURL: "https://accounts.google.com/o/oauth2/token", + AuthURL: "https://accounts.google.com/o/oauth2/auth", + TokenURL: "https://oauth2.googleapis.com/token", + AuthStyle: oauth2.AuthStyleInParams, } // JWTTokenURL is Google's OAuth 2.0 token URL to use with the JWT flow. -const JWTTokenURL = "https://accounts.google.com/o/oauth2/token" +const JWTTokenURL = "https://oauth2.googleapis.com/token" // ConfigFromJSON uses a Google Developers Console client_credentials.json // file to construct a config. @@ -150,14 +152,16 @@ func (f *credentialsFile) tokenSource(ctx context.Context, scopes []string) (oau // from Google Compute Engine (GCE)'s metadata server. It's only valid to use // this token source if your program is running on a GCE instance. // If no account is specified, "default" is used. +// If no scopes are specified, a set of default scopes are automatically granted. // Further information about retrieving access tokens from the GCE metadata // server can be found at https://cloud.google.com/compute/docs/authentication. -func ComputeTokenSource(account string) oauth2.TokenSource { - return oauth2.ReuseTokenSource(nil, computeSource{account: account}) +func ComputeTokenSource(account string, scope ...string) oauth2.TokenSource { + return oauth2.ReuseTokenSource(nil, computeSource{account: account, scopes: scope}) } type computeSource struct { account string + scopes []string } func (cs computeSource) Token() (*oauth2.Token, error) { @@ -168,7 +172,13 @@ func (cs computeSource) Token() (*oauth2.Token, error) { if acct == "" { acct = "default" } - tokenJSON, err := metadata.Get("instance/service-accounts/" + acct + "/token") + tokenURI := "instance/service-accounts/" + acct + "/token" + if len(cs.scopes) > 0 { + v := url.Values{} + v.Set("scopes", strings.Join(cs.scopes, ",")) + tokenURI = tokenURI + "?" + v.Encode() + } + tokenJSON, err := metadata.Get(tokenURI) if err != nil { return nil, err } diff --git a/vendor/golang.org/x/oauth2/google/not_go19.go b/vendor/golang.org/x/oauth2/google/not_go19.go deleted file mode 100644 index 544e40624e1..00000000000 --- a/vendor/golang.org/x/oauth2/google/not_go19.go +++ /dev/null @@ -1,54 +0,0 @@ -// 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 !go1.9 - -package google - -import ( - "golang.org/x/net/context" - "golang.org/x/oauth2" -) - -// DefaultCredentials holds Google credentials, including "Application Default Credentials". -// For more details, see: -// https://developers.google.com/accounts/docs/application-default-credentials -type DefaultCredentials struct { - ProjectID string // may be empty - TokenSource oauth2.TokenSource - - // JSON contains the raw bytes from a JSON credentials file. - // This field may be nil if authentication is provided by the - // environment and not with a credentials file, e.g. when code is - // running on Google Cloud Platform. - JSON []byte -} - -// FindDefaultCredentials searches for "Application Default Credentials". -// -// It looks for credentials in the following places, -// preferring the first location found: -// -// 1. A JSON file whose path is specified by the -// GOOGLE_APPLICATION_CREDENTIALS environment variable. -// 2. A JSON file in a location known to the gcloud command-line tool. -// On Windows, this is %APPDATA%/gcloud/application_default_credentials.json. -// On other systems, $HOME/.config/gcloud/application_default_credentials.json. -// 3. On Google App Engine it uses the appengine.AccessToken function. -// 4. On Google Compute Engine and Google App Engine Managed VMs, it fetches -// credentials from the metadata server. -// (In this final case any provided scopes are ignored.) -func FindDefaultCredentials(ctx context.Context, scopes ...string) (*DefaultCredentials, error) { - return findDefaultCredentials(ctx, scopes) -} - -// CredentialsFromJSON obtains Google credentials from a JSON value. The JSON can -// represent either a Google Developers Console client_credentials.json file (as in -// ConfigFromJSON) or a Google Developers service account key file (as in -// JWTConfigFromJSON). -// -// Note: despite the name, the returned credentials may not be Application Default Credentials. -func CredentialsFromJSON(ctx context.Context, jsonData []byte, scopes ...string) (*DefaultCredentials, error) { - return credentialsFromJSON(ctx, jsonData, scopes) -} diff --git a/vendor/golang.org/x/oauth2/google/sdk.go b/vendor/golang.org/x/oauth2/google/sdk.go index b9660caddf0..456224bc789 100644 --- a/vendor/golang.org/x/oauth2/google/sdk.go +++ b/vendor/golang.org/x/oauth2/google/sdk.go @@ -6,6 +6,7 @@ package google import ( "bufio" + "context" "encoding/json" "errors" "fmt" @@ -18,7 +19,6 @@ import ( "strings" "time" - "golang.org/x/net/context" "golang.org/x/oauth2" ) diff --git a/vendor/golang.org/x/oauth2/internal/oauth2.go b/vendor/golang.org/x/oauth2/internal/oauth2.go index fc63fcab3ff..c0ab196cf46 100644 --- a/vendor/golang.org/x/oauth2/internal/oauth2.go +++ b/vendor/golang.org/x/oauth2/internal/oauth2.go @@ -26,7 +26,7 @@ func ParseKey(key []byte) (*rsa.PrivateKey, error) { if err != nil { parsedKey, err = x509.ParsePKCS1PrivateKey(key) if err != nil { - return nil, fmt.Errorf("private key should be a PEM or plain PKSC1 or PKCS8; parse error: %v", err) + return nil, fmt.Errorf("private key should be a PEM or plain PKCS1 or PKCS8; parse error: %v", err) } } parsed, ok := parsedKey.(*rsa.PrivateKey) diff --git a/vendor/golang.org/x/oauth2/internal/token.go b/vendor/golang.org/x/oauth2/internal/token.go index 30fb315d139..355c386961d 100644 --- a/vendor/golang.org/x/oauth2/internal/token.go +++ b/vendor/golang.org/x/oauth2/internal/token.go @@ -5,19 +5,21 @@ package internal import ( + "context" "encoding/json" "errors" "fmt" "io" "io/ioutil" + "math" "mime" "net/http" "net/url" "strconv" "strings" + "sync" "time" - "golang.org/x/net/context" "golang.org/x/net/context/ctxhttp" ) @@ -61,22 +63,21 @@ type tokenJSON struct { TokenType string `json:"token_type"` RefreshToken string `json:"refresh_token"` ExpiresIn expirationTime `json:"expires_in"` // at least PayPal returns string, while most return number - Expires expirationTime `json:"expires"` // broken Facebook spelling of expires_in } func (e *tokenJSON) expiry() (t time.Time) { if v := e.ExpiresIn; v != 0 { return time.Now().Add(time.Duration(v) * time.Second) } - if v := e.Expires; v != 0 { - return time.Now().Add(time.Duration(v) * time.Second) - } return } type expirationTime int32 func (e *expirationTime) UnmarshalJSON(b []byte) error { + if len(b) == 0 || string(b) == "null" { + return nil + } var n json.Number err := json.Unmarshal(b, &n) if err != nil { @@ -86,97 +87,78 @@ func (e *expirationTime) UnmarshalJSON(b []byte) error { if err != nil { return err } + if i > math.MaxInt32 { + i = math.MaxInt32 + } *e = expirationTime(i) return nil } -var brokenAuthHeaderProviders = []string{ - "https://accounts.google.com/", - "https://api.codeswholesale.com/oauth/token", - "https://api.dropbox.com/", - "https://api.dropboxapi.com/", - "https://api.instagram.com/", - "https://api.netatmo.net/", - "https://api.odnoklassniki.ru/", - "https://api.pushbullet.com/", - "https://api.soundcloud.com/", - "https://api.twitch.tv/", - "https://app.box.com/", - "https://connect.stripe.com/", - "https://login.mailchimp.com/", - "https://login.microsoftonline.com/", - "https://login.salesforce.com/", - "https://login.windows.net", - "https://login.live.com/", - "https://oauth.sandbox.trainingpeaks.com/", - "https://oauth.trainingpeaks.com/", - "https://oauth.vk.com/", - "https://openapi.baidu.com/", - "https://slack.com/", - "https://test-sandbox.auth.corp.google.com", - "https://test.salesforce.com/", - "https://user.gini.net/", - "https://www.douban.com/", - "https://www.googleapis.com/", - "https://www.linkedin.com/", - "https://www.strava.com/oauth/", - "https://www.wunderlist.com/oauth/", - "https://api.patreon.com/", - "https://sandbox.codeswholesale.com/oauth/token", - "https://api.sipgate.com/v1/authorization/oauth", - "https://api.medium.com/v1/tokens", - "https://log.finalsurge.com/oauth/token", - "https://multisport.todaysplan.com.au/rest/oauth/access_token", - "https://whats.todaysplan.com.au/rest/oauth/access_token", -} +// RegisterBrokenAuthHeaderProvider previously did something. It is now a no-op. +// +// Deprecated: this function no longer does anything. Caller code that +// wants to avoid potential extra HTTP requests made during +// auto-probing of the provider's auth style should set +// Endpoint.AuthStyle. +func RegisterBrokenAuthHeaderProvider(tokenURL string) {} + +// AuthStyle is a copy of the golang.org/x/oauth2 package's AuthStyle type. +type AuthStyle int -// brokenAuthHeaderDomains lists broken providers that issue dynamic endpoints. -var brokenAuthHeaderDomains = []string{ - ".auth0.com", - ".force.com", - ".myshopify.com", - ".okta.com", - ".oktapreview.com", +const ( + AuthStyleUnknown AuthStyle = 0 + AuthStyleInParams AuthStyle = 1 + AuthStyleInHeader AuthStyle = 2 +) + +// authStyleCache is the set of tokenURLs we've successfully used via +// RetrieveToken and which style auth we ended up using. +// It's called a cache, but it doesn't (yet?) shrink. It's expected that +// the set of OAuth2 servers a program contacts over time is fixed and +// small. +var authStyleCache struct { + sync.Mutex + m map[string]AuthStyle // keyed by tokenURL } -func RegisterBrokenAuthHeaderProvider(tokenURL string) { - brokenAuthHeaderProviders = append(brokenAuthHeaderProviders, tokenURL) +// ResetAuthCache resets the global authentication style cache used +// for AuthStyleUnknown token requests. +func ResetAuthCache() { + authStyleCache.Lock() + defer authStyleCache.Unlock() + authStyleCache.m = nil } -// providerAuthHeaderWorks reports whether the OAuth2 server identified by the tokenURL -// implements the OAuth2 spec correctly -// See https://code.google.com/p/goauth2/issues/detail?id=31 for background. -// In summary: -// - Reddit only accepts client secret in the Authorization header -// - Dropbox accepts either it in URL param or Auth header, but not both. -// - Google only accepts URL param (not spec compliant?), not Auth header -// - Stripe only accepts client secret in Auth header with Bearer method, not Basic -func providerAuthHeaderWorks(tokenURL string) bool { - for _, s := range brokenAuthHeaderProviders { - if strings.HasPrefix(tokenURL, s) { - // Some sites fail to implement the OAuth2 spec fully. - return false - } - } +// lookupAuthStyle reports which auth style we last used with tokenURL +// when calling RetrieveToken and whether we have ever done so. +func lookupAuthStyle(tokenURL string) (style AuthStyle, ok bool) { + authStyleCache.Lock() + defer authStyleCache.Unlock() + style, ok = authStyleCache.m[tokenURL] + return +} - if u, err := url.Parse(tokenURL); err == nil { - for _, s := range brokenAuthHeaderDomains { - if strings.HasSuffix(u.Host, s) { - return false - } - } +// setAuthStyle adds an entry to authStyleCache, documented above. +func setAuthStyle(tokenURL string, v AuthStyle) { + authStyleCache.Lock() + defer authStyleCache.Unlock() + if authStyleCache.m == nil { + authStyleCache.m = make(map[string]AuthStyle) } - - // Assume the provider implements the spec properly - // otherwise. We can add more exceptions as they're - // discovered. We will _not_ be adding configurable hooks - // to this package to let users select server bugs. - return true + authStyleCache.m[tokenURL] = v } -func RetrieveToken(ctx context.Context, clientID, clientSecret, tokenURL string, v url.Values) (*Token, error) { - bustedAuth := !providerAuthHeaderWorks(tokenURL) - if bustedAuth { +// newTokenRequest returns a new *http.Request to retrieve a new token +// from tokenURL using the provided clientID, clientSecret, and POST +// body parameters. +// +// inParams is whether the clientID & clientSecret should be encoded +// as the POST body. An 'inParams' value of true means to send it in +// the POST body (along with any values in v); false means to send it +// in the Authorization header. +func newTokenRequest(tokenURL, clientID, clientSecret string, v url.Values, authStyle AuthStyle) (*http.Request, error) { + if authStyle == AuthStyleInParams { + v = cloneURLValues(v) if clientID != "" { v.Set("client_id", clientID) } @@ -189,15 +171,70 @@ func RetrieveToken(ctx context.Context, clientID, clientSecret, tokenURL string, return nil, err } req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - if !bustedAuth { + if authStyle == AuthStyleInHeader { req.SetBasicAuth(url.QueryEscape(clientID), url.QueryEscape(clientSecret)) } + return req, nil +} + +func cloneURLValues(v url.Values) url.Values { + v2 := make(url.Values, len(v)) + for k, vv := range v { + v2[k] = append([]string(nil), vv...) + } + return v2 +} + +func RetrieveToken(ctx context.Context, clientID, clientSecret, tokenURL string, v url.Values, authStyle AuthStyle) (*Token, error) { + needsAuthStyleProbe := authStyle == 0 + if needsAuthStyleProbe { + if style, ok := lookupAuthStyle(tokenURL); ok { + authStyle = style + needsAuthStyleProbe = false + } else { + authStyle = AuthStyleInHeader // the first way we'll try + } + } + req, err := newTokenRequest(tokenURL, clientID, clientSecret, v, authStyle) + if err != nil { + return nil, err + } + token, err := doTokenRoundTrip(ctx, req) + if err != nil && needsAuthStyleProbe { + // If we get an error, assume the server wants the + // clientID & clientSecret in a different form. + // See https://code.google.com/p/goauth2/issues/detail?id=31 for background. + // In summary: + // - Reddit only accepts client secret in the Authorization header + // - Dropbox accepts either it in URL param or Auth header, but not both. + // - Google only accepts URL param (not spec compliant?), not Auth header + // - Stripe only accepts client secret in Auth header with Bearer method, not Basic + // + // We used to maintain a big table in this code of all the sites and which way + // they went, but maintaining it didn't scale & got annoying. + // So just try both ways. + authStyle = AuthStyleInParams // the second way we'll try + req, _ = newTokenRequest(tokenURL, clientID, clientSecret, v, authStyle) + token, err = doTokenRoundTrip(ctx, req) + } + if needsAuthStyleProbe && err == nil { + setAuthStyle(tokenURL, authStyle) + } + // Don't overwrite `RefreshToken` with an empty value + // if this was a token refreshing request. + if token != nil && token.RefreshToken == "" { + token.RefreshToken = v.Get("refresh_token") + } + return token, err +} + +func doTokenRoundTrip(ctx context.Context, req *http.Request) (*Token, error) { r, err := ctxhttp.Do(ctx, ContextClient(ctx), req) if err != nil { return nil, err } - defer r.Body.Close() body, err := ioutil.ReadAll(io.LimitReader(r.Body, 1<<20)) + r.Body.Close() if err != nil { return nil, fmt.Errorf("oauth2: cannot fetch token: %v", err) } @@ -223,12 +260,6 @@ func RetrieveToken(ctx context.Context, clientID, clientSecret, tokenURL string, Raw: vals, } e := vals.Get("expires_in") - if e == "" { - // TODO(jbd): Facebook's OAuth2 implementation is broken and - // returns expires_in field in expires. Remove the fallback to expires, - // when Facebook fixes their implementation. - e = vals.Get("expires") - } expires, _ := strconv.Atoi(e) if expires != 0 { token.Expiry = time.Now().Add(time.Duration(expires) * time.Second) @@ -247,13 +278,8 @@ func RetrieveToken(ctx context.Context, clientID, clientSecret, tokenURL string, } json.Unmarshal(body, &token.Raw) // no error checks for optional fields } - // Don't overwrite `RefreshToken` with an empty value - // if this was a token refreshing request. - if token.RefreshToken == "" { - token.RefreshToken = v.Get("refresh_token") - } if token.AccessToken == "" { - return token, errors.New("oauth2: server response missing access_token") + return nil, errors.New("oauth2: server response missing access_token") } return token, nil } diff --git a/vendor/golang.org/x/oauth2/internal/transport.go b/vendor/golang.org/x/oauth2/internal/transport.go index d16f9ae1fea..572074a637d 100644 --- a/vendor/golang.org/x/oauth2/internal/transport.go +++ b/vendor/golang.org/x/oauth2/internal/transport.go @@ -5,9 +5,8 @@ package internal import ( + "context" "net/http" - - "golang.org/x/net/context" ) // HTTPClient is the context key to use with golang.org/x/net/context's diff --git a/vendor/golang.org/x/oauth2/jwt/jwt.go b/vendor/golang.org/x/oauth2/jwt/jwt.go index e08f3159590..99f3e0a32c8 100644 --- a/vendor/golang.org/x/oauth2/jwt/jwt.go +++ b/vendor/golang.org/x/oauth2/jwt/jwt.go @@ -9,6 +9,7 @@ package jwt import ( + "context" "encoding/json" "fmt" "io" @@ -18,7 +19,6 @@ import ( "strings" "time" - "golang.org/x/net/context" "golang.org/x/oauth2" "golang.org/x/oauth2/internal" "golang.org/x/oauth2/jws" @@ -61,6 +61,11 @@ type Config struct { // Expires optionally specifies how long the token is valid for. Expires time.Duration + + // Audience optionally specifies the intended audience of the + // request. If empty, the value of TokenURL is used as the + // intended audience. + Audience string } // TokenSource returns a JWT TokenSource using the configuration @@ -105,6 +110,9 @@ func (js jwtSource) Token() (*oauth2.Token, error) { if t := js.conf.Expires; t > 0 { claimSet.Exp = time.Now().Add(t).Unix() } + if aud := js.conf.Audience; aud != "" { + claimSet.Aud = aud + } h := *defaultHeader h.KeyID = js.conf.PrivateKeyID payload, err := jws.Encode(&h, claimSet, pk) diff --git a/vendor/golang.org/x/oauth2/oauth2.go b/vendor/golang.org/x/oauth2/oauth2.go index a047a5f98b6..428283f0b01 100644 --- a/vendor/golang.org/x/oauth2/oauth2.go +++ b/vendor/golang.org/x/oauth2/oauth2.go @@ -3,19 +3,20 @@ // license that can be found in the LICENSE file. // Package oauth2 provides support for making -// OAuth2 authorized and authenticated HTTP requests. +// OAuth2 authorized and authenticated HTTP requests, +// as specified in RFC 6749. // It can additionally grant authorization with Bearer JWT. package oauth2 // import "golang.org/x/oauth2" import ( "bytes" + "context" "errors" "net/http" "net/url" "strings" "sync" - "golang.org/x/net/context" "golang.org/x/oauth2/internal" ) @@ -25,17 +26,13 @@ import ( // Deprecated: Use context.Background() or context.TODO() instead. var NoContext = context.TODO() -// RegisterBrokenAuthHeaderProvider registers an OAuth2 server -// identified by the tokenURL prefix as an OAuth2 implementation -// which doesn't support the HTTP Basic authentication -// scheme to authenticate with the authorization server. -// Once a server is registered, credentials (client_id and client_secret) -// will be passed as query parameters rather than being present -// in the Authorization header. -// See https://code.google.com/p/goauth2/issues/detail?id=31 for background. -func RegisterBrokenAuthHeaderProvider(tokenURL string) { - internal.RegisterBrokenAuthHeaderProvider(tokenURL) -} +// RegisterBrokenAuthHeaderProvider previously did something. It is now a no-op. +// +// Deprecated: this function no longer does anything. Caller code that +// wants to avoid potential extra HTTP requests made during +// auto-probing of the provider's auth style should set +// Endpoint.AuthStyle. +func RegisterBrokenAuthHeaderProvider(tokenURL string) {} // Config describes a typical 3-legged OAuth2 flow, with both the // client application information and the server's endpoint URLs. @@ -70,13 +67,38 @@ type TokenSource interface { Token() (*Token, error) } -// Endpoint contains the OAuth 2.0 provider's authorization and token +// Endpoint represents an OAuth 2.0 provider's authorization and token // endpoint URLs. type Endpoint struct { AuthURL string TokenURL string + + // AuthStyle optionally specifies how the endpoint wants the + // client ID & client secret sent. The zero value means to + // auto-detect. + AuthStyle AuthStyle } +// AuthStyle represents how requests for tokens are authenticated +// to the server. +type AuthStyle int + +const ( + // AuthStyleAutoDetect means to auto-detect which authentication + // style the provider wants by trying both ways and caching + // the successful way for the future. + AuthStyleAutoDetect AuthStyle = 0 + + // AuthStyleInParams sends the "client_id" and "client_secret" + // in the POST body as application/x-www-form-urlencoded parameters. + AuthStyleInParams AuthStyle = 1 + + // AuthStyleInHeader sends the client_id and client_password + // using HTTP Basic Authorization. This is an optional style + // described in the OAuth2 RFC 6749 section 2.3.1. + AuthStyleInHeader AuthStyle = 2 +) + var ( // AccessTypeOnline and AccessTypeOffline are options passed // to the Options.AuthCodeURL method. They modify the @@ -123,6 +145,8 @@ func SetAuthURLParam(key, value string) AuthCodeOption { // // Opts may include AccessTypeOnline or AccessTypeOffline, as well // as ApprovalForce. +// It can also be used to pass the PKCE challenge. +// See https://www.oauth.com/oauth2-servers/pkce/ for more info. func (c *Config) AuthCodeURL(state string, opts ...AuthCodeOption) string { var buf bytes.Buffer buf.WriteString(c.Endpoint.AuthURL) @@ -161,8 +185,7 @@ func (c *Config) AuthCodeURL(state string, opts ...AuthCodeOption) string { // and when other authorization grant types are not available." // See https://tools.ietf.org/html/rfc6749#section-4.3 for more info. // -// The HTTP client to use is derived from the context. -// If nil, http.DefaultClient is used. +// The provided context optionally controls which HTTP client is used. See the HTTPClient variable. func (c *Config) PasswordCredentialsToken(ctx context.Context, username, password string) (*Token, error) { v := url.Values{ "grant_type": {"password"}, @@ -180,12 +203,14 @@ func (c *Config) PasswordCredentialsToken(ctx context.Context, username, passwor // It is used after a resource provider redirects the user back // to the Redirect URI (the URL obtained from AuthCodeURL). // -// The HTTP client to use is derived from the context. -// If a client is not provided via the context, http.DefaultClient is used. +// The provided context optionally controls which HTTP client is used. See the HTTPClient variable. // // The code will be in the *http.Request.FormValue("code"). Before // calling Exchange, be sure to validate FormValue("state"). -func (c *Config) Exchange(ctx context.Context, code string) (*Token, error) { +// +// Opts may include the PKCE verifier code if previously used in AuthCodeURL. +// See https://www.oauth.com/oauth2-servers/pkce/ for more info. +func (c *Config) Exchange(ctx context.Context, code string, opts ...AuthCodeOption) (*Token, error) { v := url.Values{ "grant_type": {"authorization_code"}, "code": {code}, @@ -193,6 +218,9 @@ func (c *Config) Exchange(ctx context.Context, code string) (*Token, error) { if c.RedirectURL != "" { v.Set("redirect_uri", c.RedirectURL) } + for _, opt := range opts { + opt.setValue(v) + } return retrieveToken(ctx, c, v) } diff --git a/vendor/golang.org/x/oauth2/token.go b/vendor/golang.org/x/oauth2/token.go index 34db8cdc8a3..822720341af 100644 --- a/vendor/golang.org/x/oauth2/token.go +++ b/vendor/golang.org/x/oauth2/token.go @@ -5,6 +5,7 @@ package oauth2 import ( + "context" "fmt" "net/http" "net/url" @@ -12,7 +13,6 @@ import ( "strings" "time" - "golang.org/x/net/context" "golang.org/x/oauth2/internal" ) @@ -118,13 +118,16 @@ func (t *Token) Extra(key string) interface{} { return v } +// timeNow is time.Now but pulled out as a variable for tests. +var timeNow = time.Now + // expired reports whether the token is expired. // t must be non-nil. func (t *Token) expired() bool { if t.Expiry.IsZero() { return false } - return t.Expiry.Round(0).Add(-expiryDelta).Before(time.Now()) + return t.Expiry.Round(0).Add(-expiryDelta).Before(timeNow()) } // Valid reports whether t is non-nil, has an AccessToken, and is not expired. @@ -151,7 +154,7 @@ func tokenFromInternal(t *internal.Token) *Token { // This token is then mapped from *internal.Token into an *oauth2.Token which is returned along // with an error.. func retrieveToken(ctx context.Context, c *Config, v url.Values) (*Token, error) { - tk, err := internal.RetrieveToken(ctx, c.ClientID, c.ClientSecret, c.Endpoint.TokenURL, v) + tk, err := internal.RetrieveToken(ctx, c.ClientID, c.ClientSecret, c.Endpoint.TokenURL, v, internal.AuthStyle(c.Endpoint.AuthStyle)) if err != nil { if rErr, ok := err.(*internal.RetrieveError); ok { return nil, (*RetrieveError)(rErr) diff --git a/vendor/golang.org/x/oauth2/transport.go b/vendor/golang.org/x/oauth2/transport.go index 92ac7e2531f..aa0d34f1e0e 100644 --- a/vendor/golang.org/x/oauth2/transport.go +++ b/vendor/golang.org/x/oauth2/transport.go @@ -31,9 +31,17 @@ type Transport struct { } // RoundTrip authorizes and authenticates the request with an -// access token. If no token exists or token is expired, -// tries to refresh/fetch a new token. +// access token from Transport's Source. func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) { + reqBodyClosed := false + if req.Body != nil { + defer func() { + if !reqBodyClosed { + req.Body.Close() + } + }() + } + if t.Source == nil { return nil, errors.New("oauth2: Transport's Source is nil") } @@ -46,6 +54,10 @@ func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) { token.SetAuthHeader(req2) t.setModReq(req, req2) res, err := t.base().RoundTrip(req2) + + // req.Body is assumed to have been closed by the base RoundTripper. + reqBodyClosed = true + if err != nil { t.setModReq(req, nil) return nil, err diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/runtime/scheme/scheme.go b/vendor/sigs.k8s.io/controller-runtime/pkg/runtime/scheme/scheme.go deleted file mode 100644 index 79868214e34..00000000000 --- a/vendor/sigs.k8s.io/controller-runtime/pkg/runtime/scheme/scheme.go +++ /dev/null @@ -1,56 +0,0 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT 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 scheme - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" -) - -// Builder builds a new Scheme for mapping go types to Kubernetes GroupVersionKinds. -type Builder struct { - GroupVersion schema.GroupVersion - runtime.SchemeBuilder -} - -// Register adds one or objects to the SchemeBuilder so they can be added to a Scheme. Register mutates bld. -func (bld *Builder) Register(object ...runtime.Object) *Builder { - bld.SchemeBuilder.Register(func(scheme *runtime.Scheme) error { - scheme.AddKnownTypes(bld.GroupVersion, object...) - metav1.AddToGroupVersion(scheme, bld.GroupVersion) - return nil - }) - return bld -} - -// RegisterAll registers all types from the Builder argument. RegisterAll mutates bld. -func (bld *Builder) RegisterAll(b *Builder) *Builder { - bld.SchemeBuilder = append(bld.SchemeBuilder, b.SchemeBuilder...) - return bld -} - -// AddToScheme adds all registered types to s. -func (bld *Builder) AddToScheme(s *runtime.Scheme) error { - return bld.SchemeBuilder.AddToScheme(s) -} - -// Build returns a new Scheme containing the registered types. -func (bld *Builder) Build() (*runtime.Scheme, error) { - s := runtime.NewScheme() - return s, bld.AddToScheme(s) -} From db65b1503819b55dcee1858335236e73a368c730 Mon Sep 17 00:00:00 2001 From: Scott Nichols Date: Wed, 24 Apr 2019 13:26:35 -0700 Subject: [PATCH 13/25] fix yaml. --- config/500-controller.yaml | 1 + config/500-source-controller.yaml | 10 ++++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/config/500-controller.yaml b/config/500-controller.yaml index e28a2633725..2cb7d815c06 100644 --- a/config/500-controller.yaml +++ b/config/500-controller.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: apps/v1 kind: Deployment metadata: diff --git a/config/500-source-controller.yaml b/config/500-source-controller.yaml index fdf2bbbeaab..4d0265fa6f0 100644 --- a/config/500-source-controller.yaml +++ b/config/500-source-controller.yaml @@ -15,7 +15,7 @@ apiVersion: apps/v1 kind: Deployment metadata: - name: controller + name: source-controller namespace: knative-eventing labels: eventing.knative.dev/release: devel @@ -34,9 +34,9 @@ spec: spec: serviceAccountName: knative-controller containers: - - name: controller - # This is the Go import path for the binary that is containerized - # and substituted here. + - name: controller + # This is the Go import path for the binary that is containerized + # and substituted here. image: github.com/knative/eventing/cmd/source-controller resources: requests: @@ -59,6 +59,8 @@ spec: - name: CONFIG_LOGGING_NAME value: config-logging - name: CRONJOB_RA_IMAGE + # This is the Go import path for cron job receive adapter binary + # that is containerized and substituted here. value: github.com/knative/eventing/cmd/cronjob_receive_adapter volumes: - name: config-logging From 1e36900533debafce08137e411556d445ccc2fd1 Mon Sep 17 00:00:00 2001 From: Scott Nichols Date: Wed, 24 Apr 2019 13:31:13 -0700 Subject: [PATCH 14/25] use sources. --- cmd/source-controller/main.go | 4 ++-- config/400-source-controller-service.yaml | 6 +++--- ...source-controller.yaml => 500-sources-controller.yaml} | 8 ++++---- pkg/logconfig/config.go | 4 ++-- 4 files changed, 11 insertions(+), 11 deletions(-) rename config/{500-source-controller.yaml => 500-sources-controller.yaml} (92%) diff --git a/cmd/source-controller/main.go b/cmd/source-controller/main.go index 850b9049e5f..f58d746034c 100644 --- a/cmd/source-controller/main.go +++ b/cmd/source-controller/main.go @@ -50,7 +50,7 @@ func main() { logger, atomicLevel := setupLogger() defer logger.Sync() - logger = logger.With(zap.String(logkey.ControllerType, logconfig.SourceController)) + logger = logger.With(zap.String(logkey.ControllerType, logconfig.SourcesController)) // set up signals so we handle the first shutdown signal gracefully stopCh := signals.SetupSignalHandler() @@ -92,7 +92,7 @@ func main() { } // Watch the logging config map and dynamically update logging levels. - opt.ConfigMapWatcher.Watch(logconfig.ConfigMapName(), logging.UpdateLevelFromConfigMap(logger, atomicLevel, logconfig.SourceController)) + opt.ConfigMapWatcher.Watch(logconfig.ConfigMapName(), logging.UpdateLevelFromConfigMap(logger, atomicLevel, logconfig.SourcesController)) // TODO: Watch the observability config map and dynamically update metrics exporter. //opt.ConfigMapWatcher.Watch(metrics.ObservabilityConfigName, metrics.UpdateExporterFromConfigMap(component, logger)) if err := opt.ConfigMapWatcher.Start(stopCh); err != nil { diff --git a/config/400-source-controller-service.yaml b/config/400-source-controller-service.yaml index d1a8038385c..3b37422a88b 100644 --- a/config/400-source-controller-service.yaml +++ b/config/400-source-controller-service.yaml @@ -16,9 +16,9 @@ apiVersion: v1 kind: Service metadata: labels: - app: source-controller + app: sources-controller serving.knative.dev/release: devel - name: source-controller + name: sources-controller namespace: knative-eventing spec: ports: @@ -27,4 +27,4 @@ spec: protocol: TCP targetPort: 9090 selector: - app: source-controller \ No newline at end of file + app: sources-controller \ No newline at end of file diff --git a/config/500-source-controller.yaml b/config/500-sources-controller.yaml similarity index 92% rename from config/500-source-controller.yaml rename to config/500-sources-controller.yaml index 4d0265fa6f0..76721b5b540 100644 --- a/config/500-source-controller.yaml +++ b/config/500-sources-controller.yaml @@ -15,7 +15,7 @@ apiVersion: apps/v1 kind: Deployment metadata: - name: source-controller + name: sources-controller namespace: knative-eventing labels: eventing.knative.dev/release: devel @@ -23,13 +23,13 @@ spec: replicas: 1 selector: matchLabels: - app: source-controller + app: sources-controller template: metadata: annotations: sidecar.istio.io/inject: "false" labels: - app: source-controller + app: sources-controller eventing.knative.dev/release: devel spec: serviceAccountName: knative-controller @@ -37,7 +37,7 @@ spec: - name: controller # This is the Go import path for the binary that is containerized # and substituted here. - image: github.com/knative/eventing/cmd/source-controller + image: github.com/knative/eventing/cmd/sources-controller resources: requests: cpu: 100m diff --git a/pkg/logconfig/config.go b/pkg/logconfig/config.go index 9ae1c88da71..48b3d842cab 100644 --- a/pkg/logconfig/config.go +++ b/pkg/logconfig/config.go @@ -33,8 +33,8 @@ const ( // Controller is the name of the override key used inside of the logging config for Controller. Controller = "controller" - // SourceController is the name of the override key used inside of the logging config for Controller. - SourceController = "source-controller" + // SourcesController is the name of the override key used inside of the logging config for Sources Controller. + SourcesController = "sources-controller" // Webhook is the name of the override key used inside of the logging config for Webhook Controller. WebhookNameEnv = "WEBHOOK_NAME" From 409faf744f6e269f9e27f2419dd50cf727504b74 Mon Sep 17 00:00:00 2001 From: Scott Nichols Date: Wed, 24 Apr 2019 13:34:50 -0700 Subject: [PATCH 15/25] 2019 --- cmd/source-controller/main.go | 2 +- pkg/adapter/cronjobevents/adapter.go | 2 +- pkg/adapter/cronjobevents/adapter_test.go | 2 +- pkg/apis/duck/v1alpha1/doc.go | 5 +++- pkg/apis/duck/v1alpha1/subscribable_types.go | 28 +++++++++---------- .../duck/v1alpha1/subscribable_types_test.go | 28 +++++++++---------- pkg/apis/sources/v1alpha1/register.go | 2 +- 7 files changed, 36 insertions(+), 33 deletions(-) diff --git a/cmd/source-controller/main.go b/cmd/source-controller/main.go index f58d746034c..6abe075e348 100644 --- a/cmd/source-controller/main.go +++ b/cmd/source-controller/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. diff --git a/pkg/adapter/cronjobevents/adapter.go b/pkg/adapter/cronjobevents/adapter.go index 0ff3bfa9743..ee3146e3472 100644 --- a/pkg/adapter/cronjobevents/adapter.go +++ b/pkg/adapter/cronjobevents/adapter.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/adapter/cronjobevents/adapter_test.go b/pkg/adapter/cronjobevents/adapter_test.go index 8416664f7b9..ae9ca48dd42 100644 --- a/pkg/adapter/cronjobevents/adapter_test.go +++ b/pkg/adapter/cronjobevents/adapter_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/duck/v1alpha1/doc.go b/pkg/apis/duck/v1alpha1/doc.go index 3e5d1e3bc5a..5019094b1e5 100644 --- a/pkg/apis/duck/v1alpha1/doc.go +++ b/pkg/apis/duck/v1alpha1/doc.go @@ -1,9 +1,12 @@ /* -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. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. diff --git a/pkg/apis/duck/v1alpha1/subscribable_types.go b/pkg/apis/duck/v1alpha1/subscribable_types.go index 740a035ead3..407a7912407 100644 --- a/pkg/apis/duck/v1alpha1/subscribable_types.go +++ b/pkg/apis/duck/v1alpha1/subscribable_types.go @@ -1,18 +1,18 @@ /* - * 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. - */ +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/duck/v1alpha1/subscribable_types_test.go b/pkg/apis/duck/v1alpha1/subscribable_types_test.go index ccc6512ab36..5052347a97f 100644 --- a/pkg/apis/duck/v1alpha1/subscribable_types_test.go +++ b/pkg/apis/duck/v1alpha1/subscribable_types_test.go @@ -1,18 +1,18 @@ /* - * 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. - */ +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/sources/v1alpha1/register.go b/pkg/apis/sources/v1alpha1/register.go index fa8640fc93f..a170bc79c54 100644 --- a/pkg/apis/sources/v1alpha1/register.go +++ b/pkg/apis/sources/v1alpha1/register.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. From 2b1380f94ca239a7bbf2ca64e96589a03a4a7ec9 Mon Sep 17 00:00:00 2001 From: Scott Nichols Date: Wed, 24 Apr 2019 13:40:35 -0700 Subject: [PATCH 16/25] use the real word, not core. --- cmd/controller/main.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cmd/controller/main.go b/cmd/controller/main.go index 6d0096c1e3a..34aee80848a 100644 --- a/cmd/controller/main.go +++ b/cmd/controller/main.go @@ -111,8 +111,8 @@ func startPkgController(stopCh <-chan struct{}, cfg *rest.Config, logger *zap.Su brokerInformer := eventingInformerFactory.Eventing().V1alpha1().Brokers() // Kube - coreServiceInformer := kubeInformerFactory.Core().V1().Services() - coreNamespaceInformer := kubeInformerFactory.Core().V1().Namespaces() + serviceInformer := kubeInformerFactory.Core().V1().Services() + namespaceInformer := kubeInformerFactory.Core().V1().Namespaces() configMapInformer := kubeInformerFactory.Core().V1().ConfigMaps() // Build all of our controllers, with the clients constructed above. @@ -125,7 +125,7 @@ func startPkgController(stopCh <-chan struct{}, cfg *rest.Config, logger *zap.Su ), namespace.NewController( opt, - coreNamespaceInformer, + namespaceInformer, ), channel.NewController( opt, @@ -137,7 +137,7 @@ func startPkgController(stopCh <-chan struct{}, cfg *rest.Config, logger *zap.Su channelInformer, subscriptionInformer, brokerInformer, - coreServiceInformer, + serviceInformer, ), } if len(controllers) != numControllers { @@ -163,8 +163,8 @@ func startPkgController(stopCh <-chan struct{}, cfg *rest.Config, logger *zap.Su triggerInformer.Informer(), // Kube configMapInformer.Informer(), - coreServiceInformer.Informer(), - coreNamespaceInformer.Informer(), + serviceInformer.Informer(), + namespaceInformer.Informer(), ); err != nil { logger.Fatalf("Failed to start informers: %v", err) } From ce08dd0bd2401ddafb37718a16049b1099d43431 Mon Sep 17 00:00:00 2001 From: Scott Nichols Date: Wed, 24 Apr 2019 13:42:50 -0700 Subject: [PATCH 17/25] source -> sources. --- cmd/{source-controller => sources-controller}/kodata/HEAD | 0 cmd/{source-controller => sources-controller}/kodata/LICENSE | 0 .../kodata/VENDOR-LICENSE | 0 cmd/{source-controller => sources-controller}/main.go | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename cmd/{source-controller => sources-controller}/kodata/HEAD (100%) rename cmd/{source-controller => sources-controller}/kodata/LICENSE (100%) rename cmd/{source-controller => sources-controller}/kodata/VENDOR-LICENSE (100%) rename cmd/{source-controller => sources-controller}/main.go (100%) diff --git a/cmd/source-controller/kodata/HEAD b/cmd/sources-controller/kodata/HEAD similarity index 100% rename from cmd/source-controller/kodata/HEAD rename to cmd/sources-controller/kodata/HEAD diff --git a/cmd/source-controller/kodata/LICENSE b/cmd/sources-controller/kodata/LICENSE similarity index 100% rename from cmd/source-controller/kodata/LICENSE rename to cmd/sources-controller/kodata/LICENSE diff --git a/cmd/source-controller/kodata/VENDOR-LICENSE b/cmd/sources-controller/kodata/VENDOR-LICENSE similarity index 100% rename from cmd/source-controller/kodata/VENDOR-LICENSE rename to cmd/sources-controller/kodata/VENDOR-LICENSE diff --git a/cmd/source-controller/main.go b/cmd/sources-controller/main.go similarity index 100% rename from cmd/source-controller/main.go rename to cmd/sources-controller/main.go From cdc7107594af2d02e5a52c16d9afb98959e17543 Mon Sep 17 00:00:00 2001 From: Scott Nichols Date: Wed, 24 Apr 2019 13:48:09 -0700 Subject: [PATCH 18/25] fix yaml. --- config/500-sources-controller.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/500-sources-controller.yaml b/config/500-sources-controller.yaml index 76721b5b540..6f77f264418 100644 --- a/config/500-sources-controller.yaml +++ b/config/500-sources-controller.yaml @@ -32,7 +32,7 @@ spec: app: sources-controller eventing.knative.dev/release: devel spec: - serviceAccountName: knative-controller + serviceAccountName: eventing-controller containers: - name: controller # This is the Go import path for the binary that is containerized From cf500ef7469b5fe49fdcc3291df2a2c6465b6a24 Mon Sep 17 00:00:00 2001 From: Scott Nichols Date: Wed, 24 Apr 2019 13:57:57 -0700 Subject: [PATCH 19/25] api for container source start. --- config/300-containersource.yaml | 89 ++++ .../v1alpha1/containersource_lifecycle.go | 92 ++++ .../containersource_lifecycle_test.go | 448 ++++++++++++++++++ .../sources/v1alpha1/containersource_types.go | 91 ++++ pkg/apis/sources/v1alpha1/register.go | 2 + pkg/apis/sources/v1alpha1/register_test.go | 2 + .../sources/v1alpha1/zz_generated.deepcopy.go | 111 +++++ .../typed/sources/v1alpha1/containersource.go | 174 +++++++ .../v1alpha1/fake/fake_containersource.go | 140 ++++++ .../v1alpha1/fake/fake_sources_client.go | 4 + .../sources/v1alpha1/generated_expansion.go | 2 + .../typed/sources/v1alpha1/sources_client.go | 5 + .../informers/externalversions/generic.go | 2 + .../sources/v1alpha1/containersource.go | 89 ++++ .../sources/v1alpha1/interface.go | 7 + .../sources/v1alpha1/containersource.go | 94 ++++ .../sources/v1alpha1/expansion_generated.go | 8 + 17 files changed, 1360 insertions(+) create mode 100644 config/300-containersource.yaml create mode 100644 pkg/apis/sources/v1alpha1/containersource_lifecycle.go create mode 100644 pkg/apis/sources/v1alpha1/containersource_lifecycle_test.go create mode 100644 pkg/apis/sources/v1alpha1/containersource_types.go create mode 100644 pkg/client/clientset/versioned/typed/sources/v1alpha1/containersource.go create mode 100644 pkg/client/clientset/versioned/typed/sources/v1alpha1/fake/fake_containersource.go create mode 100644 pkg/client/informers/externalversions/sources/v1alpha1/containersource.go create mode 100644 pkg/client/listers/sources/v1alpha1/containersource.go diff --git a/config/300-containersource.yaml b/config/300-containersource.yaml new file mode 100644 index 00000000000..ecf50df75ce --- /dev/null +++ b/config/300-containersource.yaml @@ -0,0 +1,89 @@ +# 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: + labels: + eventing.knative.dev/source: "true" + knative.dev/crd-install: "true" + name: containersources.sources.eventing.knative.dev +spec: + group: sources.eventing.knative.dev + names: + categories: + - all + - knative + - eventing + - sources + kind: ContainerSource + plural: containersources + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + args: + items: + type: string + type: array + env: + items: + type: object + type: array + image: + minLength: 1 + type: string + serviceAccountName: + type: string + sink: + type: object + type: object + status: + properties: + conditions: + items: + properties: + lastTransitionTime: + # we use a string in the stored object but a wrapper object + # at runtime. + type: string + message: + type: string + reason: + type: string + severity: + type: string + status: + type: string + type: + type: string + required: + - type + - status + type: object + type: array + sinkUri: + type: string + type: object + version: v1alpha1 diff --git a/pkg/apis/sources/v1alpha1/containersource_lifecycle.go b/pkg/apis/sources/v1alpha1/containersource_lifecycle.go new file mode 100644 index 00000000000..5848f9511ba --- /dev/null +++ b/pkg/apis/sources/v1alpha1/containersource_lifecycle.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 ( + duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" +) + +const ( + // ContainerSourceConditionReady has status True when the ContainerSource is ready to send events. + ContainerConditionReady = duckv1alpha1.ConditionReady + + // ContainerConditionSinkProvided has status True when the ContainerSource has been configured with a sink target. + ContainerConditionSinkProvided duckv1alpha1.ConditionType = "SinkProvided" + + // ContainerConditionDeployed has status True when the ContainerSource has had it's deployment created. + ContainerConditionDeployed duckv1alpha1.ConditionType = "Deployed" +) + +var containerCondSet = duckv1alpha1.NewLivingConditionSet( + ContainerConditionSinkProvided, + ContainerConditionDeployed, +) + +// GetCondition returns the condition currently associated with the given type, or nil. +func (s *ContainerSourceStatus) GetCondition(t duckv1alpha1.ConditionType) *duckv1alpha1.Condition { + return containerCondSet.Manage(s).GetCondition(t) +} + +// IsReady returns true if the resource is ready overall. +func (s *ContainerSourceStatus) IsReady() bool { + return containerCondSet.Manage(s).IsHappy() +} + +// InitializeConditions sets relevant unset conditions to Unknown state. +func (s *ContainerSourceStatus) InitializeConditions() { + containerCondSet.Manage(s).InitializeConditions() +} + +// MarkSink sets the condition that the source has a sink configured. +func (s *ContainerSourceStatus) MarkSink(uri string) { + s.SinkURI = uri + if len(uri) > 0 { + containerCondSet.Manage(s).MarkTrue(ContainerConditionSinkProvided) + } else { + containerCondSet.Manage(s).MarkUnknown(ContainerConditionSinkProvided, "SinkEmpty", "Sink has resolved to empty.%s", "") + } +} + +// MarkNoSink sets the condition that the source does not have a sink configured. +func (s *ContainerSourceStatus) MarkNoSink(reason, messageFormat string, messageA ...interface{}) { + containerCondSet.Manage(s).MarkFalse(ContainerConditionSinkProvided, reason, messageFormat, messageA...) +} + +// IsDeployed returns true if the Deployed condition has status true, otherwise +// false. +func (s *ContainerSourceStatus) IsDeployed() bool { + c := containerCondSet.Manage(s).GetCondition(ContainerConditionDeployed) + if c != nil { + return c.IsTrue() + } + return false +} + +// MarkDeployed sets the condition that the source has been deployed. +func (s *ContainerSourceStatus) MarkDeployed() { + containerCondSet.Manage(s).MarkTrue(ContainerConditionDeployed) +} + +// MarkDeploying sets the condition that the source is deploying. +func (s *ContainerSourceStatus) MarkDeploying(reason, messageFormat string, messageA ...interface{}) { + containerCondSet.Manage(s).MarkUnknown(ContainerConditionDeployed, reason, messageFormat, messageA...) +} + +// MarkNotDeployed sets the condition that the source has not been deployed. +func (s *ContainerSourceStatus) MarkNotDeployed(reason, messageFormat string, messageA ...interface{}) { + containerCondSet.Manage(s).MarkFalse(ContainerConditionDeployed, reason, messageFormat, messageA...) +} diff --git a/pkg/apis/sources/v1alpha1/containersource_lifecycle_test.go b/pkg/apis/sources/v1alpha1/containersource_lifecycle_test.go new file mode 100644 index 00000000000..cde7b66f270 --- /dev/null +++ b/pkg/apis/sources/v1alpha1/containersource_lifecycle_test.go @@ -0,0 +1,448 @@ +/* +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/cmpopts" + + "github.com/google/go-cmp/cmp" + duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" + corev1 "k8s.io/api/core/v1" +) + +func TestContainerSourceStatusIsReady(t *testing.T) { + tests := []struct { + name string + s *ContainerSourceStatus + want bool + }{{ + name: "uninitialized", + s: &ContainerSourceStatus{}, + want: false, + }, { + name: "initialized", + s: func() *ContainerSourceStatus { + s := &ContainerSourceStatus{} + s.InitializeConditions() + return s + }(), + want: false, + }, { + name: "mark deployed", + s: func() *ContainerSourceStatus { + s := &ContainerSourceStatus{} + s.InitializeConditions() + s.MarkDeployed() + return s + }(), + want: false, + }, { + name: "mark sink", + s: func() *ContainerSourceStatus { + s := &ContainerSourceStatus{} + s.InitializeConditions() + s.MarkSink("uri://example") + return s + }(), + want: false, + }, { + name: "mark sink and deployed", + s: func() *ContainerSourceStatus { + s := &ContainerSourceStatus{} + s.InitializeConditions() + s.MarkSink("uri://example") + s.MarkDeployed() + return s + }(), + want: true, + }, { + name: "mark sink and deployed then no sink", + s: func() *ContainerSourceStatus { + s := &ContainerSourceStatus{} + s.InitializeConditions() + s.MarkSink("uri://example") + s.MarkDeployed() + s.MarkNoSink("Testing", "") + return s + }(), + want: false, + }, { + name: "mark sink and deployed then deploying", + s: func() *ContainerSourceStatus { + s := &ContainerSourceStatus{} + s.InitializeConditions() + s.MarkSink("uri://example") + s.MarkDeployed() + s.MarkDeploying("Testing", "") + return s + }(), + want: false, + }, { + name: "mark sink and deployed then not deployed", + s: func() *ContainerSourceStatus { + s := &ContainerSourceStatus{} + s.InitializeConditions() + s.MarkSink("uri://example") + s.MarkDeployed() + s.MarkNotDeployed("Testing", "") + return s + }(), + want: false, + }, { + name: "mark sink and not deployed then deploying then deployed", + s: func() *ContainerSourceStatus { + s := &ContainerSourceStatus{} + s.InitializeConditions() + s.MarkSink("uri://example") + s.MarkNotDeployed("MarkNotDeployed", "") + s.MarkDeploying("MarkDeploying", "") + s.MarkDeployed() + return s + }(), + want: true, + }, { + name: "mark sink empty and deployed", + s: func() *ContainerSourceStatus { + s := &ContainerSourceStatus{} + s.InitializeConditions() + s.MarkSink("") + s.MarkDeployed() + return s + }(), + want: false, + }, { + name: "mark sink empty and deployed then sink", + s: func() *ContainerSourceStatus { + s := &ContainerSourceStatus{} + s.InitializeConditions() + s.MarkSink("") + s.MarkDeployed() + s.MarkSink("uri://example") + return s + }(), + want: true, + }} + + 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 TestContainerSourceStatusGetCondition(t *testing.T) { + tests := []struct { + name string + s *ContainerSourceStatus + condQuery duckv1alpha1.ConditionType + want *duckv1alpha1.Condition + }{{ + name: "uninitialized", + s: &ContainerSourceStatus{}, + condQuery: ContainerConditionReady, + want: nil, + }, { + name: "initialized", + s: func() *ContainerSourceStatus { + s := &ContainerSourceStatus{} + s.InitializeConditions() + return s + }(), + condQuery: ContainerConditionReady, + want: &duckv1alpha1.Condition{ + Type: ContainerConditionReady, + Status: corev1.ConditionUnknown, + }, + }, { + name: "mark deployed", + s: func() *ContainerSourceStatus { + s := &ContainerSourceStatus{} + s.InitializeConditions() + s.MarkDeployed() + return s + }(), + condQuery: ContainerConditionReady, + want: &duckv1alpha1.Condition{ + Type: ContainerConditionReady, + Status: corev1.ConditionUnknown, + }, + }, { + name: "mark sink", + s: func() *ContainerSourceStatus { + s := &ContainerSourceStatus{} + s.InitializeConditions() + s.MarkSink("uri://example") + return s + }(), + condQuery: ContainerConditionReady, + want: &duckv1alpha1.Condition{ + Type: ContainerConditionReady, + Status: corev1.ConditionUnknown, + }, + }, { + name: "mark sink and deployed", + s: func() *ContainerSourceStatus { + s := &ContainerSourceStatus{} + s.InitializeConditions() + s.MarkSink("uri://example") + s.MarkDeployed() + return s + }(), + condQuery: ContainerConditionReady, + want: &duckv1alpha1.Condition{ + Type: ContainerConditionReady, + Status: corev1.ConditionTrue, + }, + }, { + name: "mark sink and deployed then no sink", + s: func() *ContainerSourceStatus { + s := &ContainerSourceStatus{} + s.InitializeConditions() + s.MarkSink("uri://example") + s.MarkDeployed() + s.MarkNoSink("Testing", "hi%s", "") + return s + }(), + condQuery: ContainerConditionReady, + want: &duckv1alpha1.Condition{ + Type: ContainerConditionReady, + Status: corev1.ConditionFalse, + Reason: "Testing", + Message: "hi", + }, + }, { + name: "mark sink and deployed then deploying", + s: func() *ContainerSourceStatus { + s := &ContainerSourceStatus{} + s.InitializeConditions() + s.MarkSink("uri://example") + s.MarkDeployed() + s.MarkDeploying("Testing", "hi%s", "") + return s + }(), + condQuery: ContainerConditionReady, + want: &duckv1alpha1.Condition{ + Type: ContainerConditionReady, + Status: corev1.ConditionUnknown, + Reason: "Testing", + Message: "hi", + }, + }, { + name: "mark sink and deployed then not deployed", + s: func() *ContainerSourceStatus { + s := &ContainerSourceStatus{} + s.InitializeConditions() + s.MarkSink("uri://example") + s.MarkDeployed() + s.MarkNotDeployed("Testing", "hi%s", "") + return s + }(), + condQuery: ContainerConditionReady, + want: &duckv1alpha1.Condition{ + Type: ContainerConditionReady, + Status: corev1.ConditionFalse, + Reason: "Testing", + Message: "hi", + }, + }, { + name: "mark sink and not deployed then deploying then deployed", + s: func() *ContainerSourceStatus { + s := &ContainerSourceStatus{} + s.InitializeConditions() + s.MarkSink("uri://example") + s.MarkNotDeployed("MarkNotDeployed", "%s", "") + s.MarkDeploying("MarkDeploying", "%s", "") + s.MarkDeployed() + return s + }(), + condQuery: ContainerConditionReady, + want: &duckv1alpha1.Condition{ + Type: ContainerConditionReady, + Status: corev1.ConditionTrue, + }, + }, { + name: "mark sink empty and deployed", + s: func() *ContainerSourceStatus { + s := &ContainerSourceStatus{} + s.InitializeConditions() + s.MarkSink("") + s.MarkDeployed() + return s + }(), + condQuery: ContainerConditionReady, + want: &duckv1alpha1.Condition{ + Type: ContainerConditionReady, + Status: corev1.ConditionUnknown, + Reason: "SinkEmpty", + Message: "Sink has resolved to empty.", + }, + }, { + name: "mark sink empty and deployed then sink", + s: func() *ContainerSourceStatus { + s := &ContainerSourceStatus{} + s.InitializeConditions() + s.MarkSink("") + s.MarkDeployed() + s.MarkSink("uri://example") + return s + }(), + condQuery: ContainerConditionReady, + want: &duckv1alpha1.Condition{ + Type: ContainerConditionReady, + Status: corev1.ConditionTrue, + }, + }} + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := test.s.GetCondition(test.condQuery) + ignoreTime := cmpopts.IgnoreFields(duckv1alpha1.Condition{}, + "LastTransitionTime", "Severity") + if diff := cmp.Diff(test.want, got, ignoreTime); diff != "" { + t.Errorf("unexpected condition (-want, +got) = %v", diff) + } + }) + } +} + +func TestContainerSourceStatusIsDeployed(t *testing.T) { + tests := []struct { + name string + s *ContainerSourceStatus + want bool + }{{ + name: "uninitialized", + s: &ContainerSourceStatus{}, + want: false, + }, { + name: "initialized", + s: func() *ContainerSourceStatus { + s := &ContainerSourceStatus{} + s.InitializeConditions() + return s + }(), + want: false, + }, { + name: "mark deployed", + s: func() *ContainerSourceStatus { + s := &ContainerSourceStatus{} + s.InitializeConditions() + s.MarkDeployed() + return s + }(), + want: true, + }, { + name: "mark sink", + s: func() *ContainerSourceStatus { + s := &ContainerSourceStatus{} + s.InitializeConditions() + s.MarkSink("uri://example") + return s + }(), + want: false, + }, { + name: "mark sink and deployed", + s: func() *ContainerSourceStatus { + s := &ContainerSourceStatus{} + s.InitializeConditions() + s.MarkSink("uri://example") + s.MarkDeployed() + return s + }(), + want: true, + }, { + name: "mark sink and deployed then no sink", + s: func() *ContainerSourceStatus { + s := &ContainerSourceStatus{} + s.InitializeConditions() + s.MarkSink("uri://example") + s.MarkDeployed() + s.MarkNoSink("Testing", "") + return s + }(), + want: true, + }, { + name: "mark sink and deployed then deploying", + s: func() *ContainerSourceStatus { + s := &ContainerSourceStatus{} + s.InitializeConditions() + s.MarkSink("uri://example") + s.MarkDeployed() + s.MarkDeploying("Testing", "") + return s + }(), + want: false, + }, { + name: "mark sink and deployed then not deployed", + s: func() *ContainerSourceStatus { + s := &ContainerSourceStatus{} + s.InitializeConditions() + s.MarkSink("uri://example") + s.MarkDeployed() + s.MarkNotDeployed("Testing", "") + return s + }(), + want: false, + }, { + name: "mark sink and not deployed then deploying then deployed", + s: func() *ContainerSourceStatus { + s := &ContainerSourceStatus{} + s.InitializeConditions() + s.MarkSink("uri://example") + s.MarkNotDeployed("MarkNotDeployed", "") + s.MarkDeploying("MarkDeploying", "") + s.MarkDeployed() + return s + }(), + want: true, + }, { + name: "mark sink empty and deployed", + s: func() *ContainerSourceStatus { + s := &ContainerSourceStatus{} + s.InitializeConditions() + s.MarkSink("") + s.MarkDeployed() + return s + }(), + want: true, + }, { + name: "mark sink empty and deployed then sink", + s: func() *ContainerSourceStatus { + s := &ContainerSourceStatus{} + s.InitializeConditions() + s.MarkSink("") + s.MarkDeployed() + s.MarkSink("uri://example") + return s + }(), + want: true, + }} + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := test.s.IsDeployed() + if diff := cmp.Diff(test.want, got); diff != "" { + t.Errorf("%s: unexpected condition (-want, +got) = %v", test.name, diff) + } + }) + } +} diff --git a/pkg/apis/sources/v1alpha1/containersource_types.go b/pkg/apis/sources/v1alpha1/containersource_types.go new file mode 100644 index 00000000000..de9d8a2bb40 --- /dev/null +++ b/pkg/apis/sources/v1alpha1/containersource_types.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 v1alpha1 + +import ( + "github.com/knative/pkg/apis/duck" + duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +k8s:defaulter-gen=true + +// ContainerSource is the Schema for the containersources API +type ContainerSource struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec ContainerSourceSpec `json:"spec,omitempty"` + Status ContainerSourceStatus `json:"status,omitempty"` +} + +// Check that ContainerSource can be validated and can be defaulted. +var _ runtime.Object = (*ContainerSource)(nil) + +// Check that ContainerSource implements the Conditions duck type. +var _ = duck.VerifyType(&ContainerSource{}, &duckv1alpha1.Conditions{}) + +// ContainerSourceSpec defines the desired state of ContainerSource +type ContainerSourceSpec struct { + // Image is the image to run inside of the container. + // +kubebuilder:validation:MinLength=1 + Image string `json:"image,omitempty"` + + // Args are passed to the ContainerSpec as they are. + Args []string `json:"args,omitempty"` + + // Env is the list of environment variables to set in the container. + // Cannot be updated. + // +optional + // +patchMergeKey=name + // +patchStrategy=merge + Env []corev1.EnvVar `json:"env,omitempty" patchStrategy:"merge" patchMergeKey:"name"` + + // ServiceAccountName is the name of the ServiceAccount to use to run this + // source. + // +optional + ServiceAccountName string `json:"serviceAccountName,omitempty"` + + // Sink is a reference to an object that will resolve to a domain name to use as the sink. + // +optional + Sink *corev1.ObjectReference `json:"sink,omitempty"` +} + +// ContainerSourceStatus defines the observed state of ContainerSource +type ContainerSourceStatus struct { + // 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"` + + // SinkURI is the current active sink URI that has been configured for the ContainerSource. + // +optional + SinkURI string `json:"sinkUri,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// ContainerSourceList contains a list of ContainerSource +type ContainerSourceList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []ContainerSource `json:"items"` +} diff --git a/pkg/apis/sources/v1alpha1/register.go b/pkg/apis/sources/v1alpha1/register.go index a170bc79c54..83556830ff3 100644 --- a/pkg/apis/sources/v1alpha1/register.go +++ b/pkg/apis/sources/v1alpha1/register.go @@ -47,6 +47,8 @@ func addKnownTypes(scheme *runtime.Scheme) error { scheme.AddKnownTypes(SchemeGroupVersion, &CronJobSource{}, &CronJobSourceList{}, + &ContainerSource{}, + &ContainerSourceList{}, ) metav1.AddToGroupVersion(scheme, SchemeGroupVersion) return nil diff --git a/pkg/apis/sources/v1alpha1/register_test.go b/pkg/apis/sources/v1alpha1/register_test.go index 2c4e17d8b5e..c111fda185c 100644 --- a/pkg/apis/sources/v1alpha1/register_test.go +++ b/pkg/apis/sources/v1alpha1/register_test.go @@ -62,6 +62,8 @@ func TestKnownTypes(t *testing.T) { for _, name := range []string{ "CronJobSource", "CronJobSourceList", + "ContainerSource", + "ContainerSourceList", } { if _, ok := types[name]; !ok { t.Errorf("Did not find %q as registered type", name) diff --git a/pkg/apis/sources/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/sources/v1alpha1/zz_generated.deepcopy.go index 686c603a5e3..29ee5bbe035 100644 --- a/pkg/apis/sources/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/sources/v1alpha1/zz_generated.deepcopy.go @@ -25,6 +25,117 @@ import ( 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 *ContainerSource) DeepCopyInto(out *ContainerSource) { + *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 ContainerSource. +func (in *ContainerSource) DeepCopy() *ContainerSource { + if in == nil { + return nil + } + out := new(ContainerSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ContainerSource) 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 *ContainerSourceList) DeepCopyInto(out *ContainerSourceList) { + *out = *in + out.TypeMeta = in.TypeMeta + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]ContainerSource, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ContainerSourceList. +func (in *ContainerSourceList) DeepCopy() *ContainerSourceList { + if in == nil { + return nil + } + out := new(ContainerSourceList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ContainerSourceList) 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 *ContainerSourceSpec) DeepCopyInto(out *ContainerSourceSpec) { + *out = *in + if in.Args != nil { + in, out := &in.Args, &out.Args + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Env != nil { + in, out := &in.Env, &out.Env + *out = make([]v1.EnvVar, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Sink != nil { + in, out := &in.Sink, &out.Sink + *out = new(v1.ObjectReference) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ContainerSourceSpec. +func (in *ContainerSourceSpec) DeepCopy() *ContainerSourceSpec { + if in == nil { + return nil + } + out := new(ContainerSourceSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ContainerSourceStatus) DeepCopyInto(out *ContainerSourceStatus) { + *out = *in + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ContainerSourceStatus. +func (in *ContainerSourceStatus) DeepCopy() *ContainerSourceStatus { + if in == nil { + return nil + } + out := new(ContainerSourceStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CronJobSource) DeepCopyInto(out *CronJobSource) { *out = *in diff --git a/pkg/client/clientset/versioned/typed/sources/v1alpha1/containersource.go b/pkg/client/clientset/versioned/typed/sources/v1alpha1/containersource.go new file mode 100644 index 00000000000..d0f935e2a85 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/sources/v1alpha1/containersource.go @@ -0,0 +1,174 @@ +/* +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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + v1alpha1 "github.com/knative/eventing/pkg/apis/sources/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" +) + +// ContainerSourcesGetter has a method to return a ContainerSourceInterface. +// A group's client should implement this interface. +type ContainerSourcesGetter interface { + ContainerSources(namespace string) ContainerSourceInterface +} + +// ContainerSourceInterface has methods to work with ContainerSource resources. +type ContainerSourceInterface interface { + Create(*v1alpha1.ContainerSource) (*v1alpha1.ContainerSource, error) + Update(*v1alpha1.ContainerSource) (*v1alpha1.ContainerSource, error) + UpdateStatus(*v1alpha1.ContainerSource) (*v1alpha1.ContainerSource, error) + Delete(name string, options *v1.DeleteOptions) error + DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error + Get(name string, options v1.GetOptions) (*v1alpha1.ContainerSource, error) + List(opts v1.ListOptions) (*v1alpha1.ContainerSourceList, error) + Watch(opts v1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.ContainerSource, err error) + ContainerSourceExpansion +} + +// containerSources implements ContainerSourceInterface +type containerSources struct { + client rest.Interface + ns string +} + +// newContainerSources returns a ContainerSources +func newContainerSources(c *SourcesV1alpha1Client, namespace string) *containerSources { + return &containerSources{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the containerSource, and returns the corresponding containerSource object, and an error if there is any. +func (c *containerSources) Get(name string, options v1.GetOptions) (result *v1alpha1.ContainerSource, err error) { + result = &v1alpha1.ContainerSource{} + err = c.client.Get(). + Namespace(c.ns). + Resource("containersources"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of ContainerSources that match those selectors. +func (c *containerSources) List(opts v1.ListOptions) (result *v1alpha1.ContainerSourceList, err error) { + result = &v1alpha1.ContainerSourceList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("containersources"). + VersionedParams(&opts, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested containerSources. +func (c *containerSources) Watch(opts v1.ListOptions) (watch.Interface, error) { + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("containersources"). + VersionedParams(&opts, scheme.ParameterCodec). + Watch() +} + +// Create takes the representation of a containerSource and creates it. Returns the server's representation of the containerSource, and an error, if there is any. +func (c *containerSources) Create(containerSource *v1alpha1.ContainerSource) (result *v1alpha1.ContainerSource, err error) { + result = &v1alpha1.ContainerSource{} + err = c.client.Post(). + Namespace(c.ns). + Resource("containersources"). + Body(containerSource). + Do(). + Into(result) + return +} + +// Update takes the representation of a containerSource and updates it. Returns the server's representation of the containerSource, and an error, if there is any. +func (c *containerSources) Update(containerSource *v1alpha1.ContainerSource) (result *v1alpha1.ContainerSource, err error) { + result = &v1alpha1.ContainerSource{} + err = c.client.Put(). + Namespace(c.ns). + Resource("containersources"). + Name(containerSource.Name). + Body(containerSource). + 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 *containerSources) UpdateStatus(containerSource *v1alpha1.ContainerSource) (result *v1alpha1.ContainerSource, err error) { + result = &v1alpha1.ContainerSource{} + err = c.client.Put(). + Namespace(c.ns). + Resource("containersources"). + Name(containerSource.Name). + SubResource("status"). + Body(containerSource). + Do(). + Into(result) + return +} + +// Delete takes name of the containerSource and deletes it. Returns an error if one occurs. +func (c *containerSources) Delete(name string, options *v1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("containersources"). + Name(name). + Body(options). + Do(). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *containerSources) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("containersources"). + VersionedParams(&listOptions, scheme.ParameterCodec). + Body(options). + Do(). + Error() +} + +// Patch applies the patch and returns the patched containerSource. +func (c *containerSources) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.ContainerSource, err error) { + result = &v1alpha1.ContainerSource{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("containersources"). + SubResource(subresources...). + Name(name). + Body(data). + Do(). + Into(result) + return +} diff --git a/pkg/client/clientset/versioned/typed/sources/v1alpha1/fake/fake_containersource.go b/pkg/client/clientset/versioned/typed/sources/v1alpha1/fake/fake_containersource.go new file mode 100644 index 00000000000..18ca2d1555e --- /dev/null +++ b/pkg/client/clientset/versioned/typed/sources/v1alpha1/fake/fake_containersource.go @@ -0,0 +1,140 @@ +/* +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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1alpha1 "github.com/knative/eventing/pkg/apis/sources/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" +) + +// FakeContainerSources implements ContainerSourceInterface +type FakeContainerSources struct { + Fake *FakeSourcesV1alpha1 + ns string +} + +var containersourcesResource = schema.GroupVersionResource{Group: "sources.eventing.knative.dev", Version: "v1alpha1", Resource: "containersources"} + +var containersourcesKind = schema.GroupVersionKind{Group: "sources.eventing.knative.dev", Version: "v1alpha1", Kind: "ContainerSource"} + +// Get takes name of the containerSource, and returns the corresponding containerSource object, and an error if there is any. +func (c *FakeContainerSources) Get(name string, options v1.GetOptions) (result *v1alpha1.ContainerSource, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(containersourcesResource, c.ns, name), &v1alpha1.ContainerSource{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ContainerSource), err +} + +// List takes label and field selectors, and returns the list of ContainerSources that match those selectors. +func (c *FakeContainerSources) List(opts v1.ListOptions) (result *v1alpha1.ContainerSourceList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(containersourcesResource, containersourcesKind, c.ns, opts), &v1alpha1.ContainerSourceList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.ContainerSourceList{ListMeta: obj.(*v1alpha1.ContainerSourceList).ListMeta} + for _, item := range obj.(*v1alpha1.ContainerSourceList).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 containerSources. +func (c *FakeContainerSources) Watch(opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(containersourcesResource, c.ns, opts)) + +} + +// Create takes the representation of a containerSource and creates it. Returns the server's representation of the containerSource, and an error, if there is any. +func (c *FakeContainerSources) Create(containerSource *v1alpha1.ContainerSource) (result *v1alpha1.ContainerSource, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(containersourcesResource, c.ns, containerSource), &v1alpha1.ContainerSource{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ContainerSource), err +} + +// Update takes the representation of a containerSource and updates it. Returns the server's representation of the containerSource, and an error, if there is any. +func (c *FakeContainerSources) Update(containerSource *v1alpha1.ContainerSource) (result *v1alpha1.ContainerSource, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(containersourcesResource, c.ns, containerSource), &v1alpha1.ContainerSource{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ContainerSource), 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 *FakeContainerSources) UpdateStatus(containerSource *v1alpha1.ContainerSource) (*v1alpha1.ContainerSource, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(containersourcesResource, "status", c.ns, containerSource), &v1alpha1.ContainerSource{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ContainerSource), err +} + +// Delete takes name of the containerSource and deletes it. Returns an error if one occurs. +func (c *FakeContainerSources) Delete(name string, options *v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteAction(containersourcesResource, c.ns, name), &v1alpha1.ContainerSource{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeContainerSources) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(containersourcesResource, c.ns, listOptions) + + _, err := c.Fake.Invokes(action, &v1alpha1.ContainerSourceList{}) + return err +} + +// Patch applies the patch and returns the patched containerSource. +func (c *FakeContainerSources) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.ContainerSource, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(containersourcesResource, c.ns, name, data, subresources...), &v1alpha1.ContainerSource{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ContainerSource), err +} diff --git a/pkg/client/clientset/versioned/typed/sources/v1alpha1/fake/fake_sources_client.go b/pkg/client/clientset/versioned/typed/sources/v1alpha1/fake/fake_sources_client.go index c2d9faeb94a..2742a8e7195 100644 --- a/pkg/client/clientset/versioned/typed/sources/v1alpha1/fake/fake_sources_client.go +++ b/pkg/client/clientset/versioned/typed/sources/v1alpha1/fake/fake_sources_client.go @@ -28,6 +28,10 @@ type FakeSourcesV1alpha1 struct { *testing.Fake } +func (c *FakeSourcesV1alpha1) ContainerSources(namespace string) v1alpha1.ContainerSourceInterface { + return &FakeContainerSources{c, namespace} +} + func (c *FakeSourcesV1alpha1) CronJobSources(namespace string) v1alpha1.CronJobSourceInterface { return &FakeCronJobSources{c, namespace} } diff --git a/pkg/client/clientset/versioned/typed/sources/v1alpha1/generated_expansion.go b/pkg/client/clientset/versioned/typed/sources/v1alpha1/generated_expansion.go index e3e7bf27492..b250cd0c5e3 100644 --- a/pkg/client/clientset/versioned/typed/sources/v1alpha1/generated_expansion.go +++ b/pkg/client/clientset/versioned/typed/sources/v1alpha1/generated_expansion.go @@ -18,4 +18,6 @@ limitations under the License. package v1alpha1 +type ContainerSourceExpansion interface{} + type CronJobSourceExpansion interface{} diff --git a/pkg/client/clientset/versioned/typed/sources/v1alpha1/sources_client.go b/pkg/client/clientset/versioned/typed/sources/v1alpha1/sources_client.go index 31733ad3ea4..dbbdbdf0392 100644 --- a/pkg/client/clientset/versioned/typed/sources/v1alpha1/sources_client.go +++ b/pkg/client/clientset/versioned/typed/sources/v1alpha1/sources_client.go @@ -27,6 +27,7 @@ import ( type SourcesV1alpha1Interface interface { RESTClient() rest.Interface + ContainerSourcesGetter CronJobSourcesGetter } @@ -35,6 +36,10 @@ type SourcesV1alpha1Client struct { restClient rest.Interface } +func (c *SourcesV1alpha1Client) ContainerSources(namespace string) ContainerSourceInterface { + return newContainerSources(c, namespace) +} + func (c *SourcesV1alpha1Client) CronJobSources(namespace string) CronJobSourceInterface { return newCronJobSources(c, namespace) } diff --git a/pkg/client/informers/externalversions/generic.go b/pkg/client/informers/externalversions/generic.go index 013b0b1e9fc..48066085062 100644 --- a/pkg/client/informers/externalversions/generic.go +++ b/pkg/client/informers/externalversions/generic.go @@ -66,6 +66,8 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource return &genericInformer{resource: resource.GroupResource(), informer: f.Eventing().V1alpha1().Triggers().Informer()}, nil // Group=sources.eventing.knative.dev, Version=v1alpha1 + case sourcesv1alpha1.SchemeGroupVersion.WithResource("containersources"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Sources().V1alpha1().ContainerSources().Informer()}, nil case sourcesv1alpha1.SchemeGroupVersion.WithResource("cronjobsources"): return &genericInformer{resource: resource.GroupResource(), informer: f.Sources().V1alpha1().CronJobSources().Informer()}, nil diff --git a/pkg/client/informers/externalversions/sources/v1alpha1/containersource.go b/pkg/client/informers/externalversions/sources/v1alpha1/containersource.go new file mode 100644 index 00000000000..e5b9f70653b --- /dev/null +++ b/pkg/client/informers/externalversions/sources/v1alpha1/containersource.go @@ -0,0 +1,89 @@ +/* +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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + time "time" + + sourcesv1alpha1 "github.com/knative/eventing/pkg/apis/sources/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/sources/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" +) + +// ContainerSourceInformer provides access to a shared informer and lister for +// ContainerSources. +type ContainerSourceInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1alpha1.ContainerSourceLister +} + +type containerSourceInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewContainerSourceInformer constructs a new informer for ContainerSource 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 NewContainerSourceInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredContainerSourceInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredContainerSourceInformer constructs a new informer for ContainerSource 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 NewFilteredContainerSourceInformer(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.SourcesV1alpha1().ContainerSources(namespace).List(options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.SourcesV1alpha1().ContainerSources(namespace).Watch(options) + }, + }, + &sourcesv1alpha1.ContainerSource{}, + resyncPeriod, + indexers, + ) +} + +func (f *containerSourceInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredContainerSourceInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *containerSourceInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&sourcesv1alpha1.ContainerSource{}, f.defaultInformer) +} + +func (f *containerSourceInformer) Lister() v1alpha1.ContainerSourceLister { + return v1alpha1.NewContainerSourceLister(f.Informer().GetIndexer()) +} diff --git a/pkg/client/informers/externalversions/sources/v1alpha1/interface.go b/pkg/client/informers/externalversions/sources/v1alpha1/interface.go index 244340025a8..9647603c828 100644 --- a/pkg/client/informers/externalversions/sources/v1alpha1/interface.go +++ b/pkg/client/informers/externalversions/sources/v1alpha1/interface.go @@ -24,6 +24,8 @@ import ( // Interface provides access to all the informers in this group version. type Interface interface { + // ContainerSources returns a ContainerSourceInformer. + ContainerSources() ContainerSourceInformer // CronJobSources returns a CronJobSourceInformer. CronJobSources() CronJobSourceInformer } @@ -39,6 +41,11 @@ func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakList return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} } +// ContainerSources returns a ContainerSourceInformer. +func (v *version) ContainerSources() ContainerSourceInformer { + return &containerSourceInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} + // CronJobSources returns a CronJobSourceInformer. func (v *version) CronJobSources() CronJobSourceInformer { return &cronJobSourceInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} diff --git a/pkg/client/listers/sources/v1alpha1/containersource.go b/pkg/client/listers/sources/v1alpha1/containersource.go new file mode 100644 index 00000000000..de44136ec26 --- /dev/null +++ b/pkg/client/listers/sources/v1alpha1/containersource.go @@ -0,0 +1,94 @@ +/* +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. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + v1alpha1 "github.com/knative/eventing/pkg/apis/sources/v1alpha1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" +) + +// ContainerSourceLister helps list ContainerSources. +type ContainerSourceLister interface { + // List lists all ContainerSources in the indexer. + List(selector labels.Selector) (ret []*v1alpha1.ContainerSource, err error) + // ContainerSources returns an object that can list and get ContainerSources. + ContainerSources(namespace string) ContainerSourceNamespaceLister + ContainerSourceListerExpansion +} + +// containerSourceLister implements the ContainerSourceLister interface. +type containerSourceLister struct { + indexer cache.Indexer +} + +// NewContainerSourceLister returns a new ContainerSourceLister. +func NewContainerSourceLister(indexer cache.Indexer) ContainerSourceLister { + return &containerSourceLister{indexer: indexer} +} + +// List lists all ContainerSources in the indexer. +func (s *containerSourceLister) List(selector labels.Selector) (ret []*v1alpha1.ContainerSource, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.ContainerSource)) + }) + return ret, err +} + +// ContainerSources returns an object that can list and get ContainerSources. +func (s *containerSourceLister) ContainerSources(namespace string) ContainerSourceNamespaceLister { + return containerSourceNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// ContainerSourceNamespaceLister helps list and get ContainerSources. +type ContainerSourceNamespaceLister interface { + // List lists all ContainerSources in the indexer for a given namespace. + List(selector labels.Selector) (ret []*v1alpha1.ContainerSource, err error) + // Get retrieves the ContainerSource from the indexer for a given namespace and name. + Get(name string) (*v1alpha1.ContainerSource, error) + ContainerSourceNamespaceListerExpansion +} + +// containerSourceNamespaceLister implements the ContainerSourceNamespaceLister +// interface. +type containerSourceNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all ContainerSources in the indexer for a given namespace. +func (s containerSourceNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.ContainerSource, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.ContainerSource)) + }) + return ret, err +} + +// Get retrieves the ContainerSource from the indexer for a given namespace and name. +func (s containerSourceNamespaceLister) Get(name string) (*v1alpha1.ContainerSource, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1alpha1.Resource("containersource"), name) + } + return obj.(*v1alpha1.ContainerSource), nil +} diff --git a/pkg/client/listers/sources/v1alpha1/expansion_generated.go b/pkg/client/listers/sources/v1alpha1/expansion_generated.go index 444c53f7032..49fe2bab0ae 100644 --- a/pkg/client/listers/sources/v1alpha1/expansion_generated.go +++ b/pkg/client/listers/sources/v1alpha1/expansion_generated.go @@ -18,6 +18,14 @@ limitations under the License. package v1alpha1 +// ContainerSourceListerExpansion allows custom methods to be added to +// ContainerSourceLister. +type ContainerSourceListerExpansion interface{} + +// ContainerSourceNamespaceListerExpansion allows custom methods to be added to +// ContainerSourceNamespaceLister. +type ContainerSourceNamespaceListerExpansion interface{} + // CronJobSourceListerExpansion allows custom methods to be added to // CronJobSourceLister. type CronJobSourceListerExpansion interface{} From e563907c02e79abca6aad834fc8a61c6c1883b10 Mon Sep 17 00:00:00 2001 From: Scott Nichols Date: Wed, 24 Apr 2019 14:29:28 -0700 Subject: [PATCH 20/25] rec done first pass. tests next. --- Gopkg.lock | 19 +- .../sources/v1alpha1/containersource_types.go | 6 + .../containersource/containersource.go | 311 +++++++++ .../containersource/containersource_test.go | 642 ++++++++++++++++++ pkg/reconciler/containersource/doc.go | 18 + .../containersource/resources/arguments.go | 36 + .../containersource/resources/deployment.go | 119 ++++ .../resources/deployment_test.go | 292 ++++++++ pkg/reconciler/cronjobsource/cronjobsource.go | 3 +- .../knative/eventing-sources/AUTHORS | 6 + .../knative/eventing-sources/LICENSE | 201 ++++++ .../apis/sources/v1alpha1/aws_sqs_types.go | 154 +++++ .../sources/v1alpha1/containersource_types.go | 157 +++++ .../apis/sources/v1alpha1/cron_job_types.go | 164 +++++ .../pkg/apis/sources/v1alpha1/doc.go | 23 + .../sources/v1alpha1/githubsource_types.go | 195 ++++++ .../v1alpha1/kuberneteseventsource_types.go | 122 ++++ .../pkg/apis/sources/v1alpha1/register.go | 45 ++ .../sources/v1alpha1/zz_generated.deepcopy.go | 562 +++++++++++++++ .../pkg/controller/sdk/finalizers_accessor.go | 82 +++ .../pkg/controller/sdk/provider.go | 74 ++ .../pkg/controller/sdk/reconciler.go | 186 +++++ .../pkg/controller/sdk/status_accessor.go | 77 +++ .../pkg/controller/testing/mock_client.go | 153 +++++ .../pkg/controller/testing/table.go | 275 ++++++++ .../containersource/resources/arguments.go | 34 + .../containersource/resources/deployment.go | 115 ++++ .../test/test_images/k8sevents/kodata/LICENSE | 1 + .../k8sevents/kodata/VENDOR-LICENSE | 1 + .../pkg/runtime/scheme/scheme.go | 56 ++ 30 files changed, 4126 insertions(+), 3 deletions(-) create mode 100644 pkg/reconciler/containersource/containersource.go create mode 100644 pkg/reconciler/containersource/containersource_test.go create mode 100644 pkg/reconciler/containersource/doc.go create mode 100644 pkg/reconciler/containersource/resources/arguments.go create mode 100644 pkg/reconciler/containersource/resources/deployment.go create mode 100644 pkg/reconciler/containersource/resources/deployment_test.go create mode 100644 vendor/github.com/knative/eventing-sources/AUTHORS create mode 100644 vendor/github.com/knative/eventing-sources/LICENSE create mode 100644 vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/aws_sqs_types.go create mode 100644 vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/containersource_types.go create mode 100644 vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/cron_job_types.go create mode 100644 vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/doc.go create mode 100644 vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/githubsource_types.go create mode 100644 vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/kuberneteseventsource_types.go create mode 100644 vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/register.go create mode 100644 vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/zz_generated.deepcopy.go create mode 100644 vendor/github.com/knative/eventing-sources/pkg/controller/sdk/finalizers_accessor.go create mode 100644 vendor/github.com/knative/eventing-sources/pkg/controller/sdk/provider.go create mode 100644 vendor/github.com/knative/eventing-sources/pkg/controller/sdk/reconciler.go create mode 100644 vendor/github.com/knative/eventing-sources/pkg/controller/sdk/status_accessor.go create mode 100644 vendor/github.com/knative/eventing-sources/pkg/controller/testing/mock_client.go create mode 100644 vendor/github.com/knative/eventing-sources/pkg/controller/testing/table.go create mode 100644 vendor/github.com/knative/eventing-sources/pkg/reconciler/containersource/resources/arguments.go create mode 100644 vendor/github.com/knative/eventing-sources/pkg/reconciler/containersource/resources/deployment.go create mode 120000 vendor/github.com/knative/eventing-sources/test/test_images/k8sevents/kodata/LICENSE create mode 120000 vendor/github.com/knative/eventing-sources/test/test_images/k8sevents/kodata/VENDOR-LICENSE create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/runtime/scheme/scheme.go diff --git a/Gopkg.lock b/Gopkg.lock index a3e5d5fbee2..e4c3580d03c 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -424,6 +424,19 @@ pruneopts = "NUT" revision = "f2b4162afba35581b6d4a50d3b8f34e33c144682" +[[projects]] + digest = "1:8d9ca74d3216fa4e3acf76a5530159cd3e5abe9cbf30519b97497da9c03af266" + name = "github.com/knative/eventing-sources" + packages = [ + "pkg/apis/sources/v1alpha1", + "pkg/controller/sdk", + "pkg/controller/testing", + "pkg/reconciler/containersource/resources", + ] + pruneopts = "NUT" + revision = "32ce3778fa1bc46ed0b0ade16d5c57f343cafa4d" + version = "v0.5.0" + [[projects]] digest = "1:57d04562d05dd4500ff1e7e47f2e62b9be0531388377a3b691a012ce70b210d5" name = "github.com/knative/pkg" @@ -1323,7 +1336,7 @@ revision = "8a9b82f00b3a86eac24681da3f9fe6c34c01cea2" [[projects]] - digest = "1:a8495647d9f03401c36b801a0644207a434f76ed9d4fc4ea80c46700f0ccc575" + digest = "1:b96e8e4a7931b07c33fdb206bfc4d27273bd599e48061500138ed69303388140" name = "sigs.k8s.io/controller-runtime" packages = [ "pkg/cache", @@ -1347,6 +1360,7 @@ "pkg/recorder", "pkg/runtime/inject", "pkg/runtime/log", + "pkg/runtime/scheme", "pkg/runtime/signals", "pkg/source", "pkg/source/internal", @@ -1375,6 +1389,9 @@ "github.com/google/go-cmp/cmp", "github.com/google/go-cmp/cmp/cmpopts", "github.com/google/uuid", + "github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1", + "github.com/knative/eventing-sources/pkg/controller/testing", + "github.com/knative/eventing-sources/pkg/reconciler/containersource/resources", "github.com/knative/pkg/apis", "github.com/knative/pkg/apis/duck", "github.com/knative/pkg/apis/duck/v1alpha1", diff --git a/pkg/apis/sources/v1alpha1/containersource_types.go b/pkg/apis/sources/v1alpha1/containersource_types.go index de9d8a2bb40..bad9c1b2639 100644 --- a/pkg/apis/sources/v1alpha1/containersource_types.go +++ b/pkg/apis/sources/v1alpha1/containersource_types.go @@ -22,6 +22,7 @@ import ( corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" ) // +genclient @@ -69,6 +70,11 @@ type ContainerSourceSpec struct { Sink *corev1.ObjectReference `json:"sink,omitempty"` } +// GetGroupVersionKind returns the GroupVersionKind. +func (s *ContainerSource) GetGroupVersionKind() schema.GroupVersionKind { + return SchemeGroupVersion.WithKind("ContainerSource") +} + // ContainerSourceStatus defines the observed state of ContainerSource type ContainerSourceStatus struct { // inherits duck/v1alpha1 Status, which currently provides: diff --git a/pkg/reconciler/containersource/containersource.go b/pkg/reconciler/containersource/containersource.go new file mode 100644 index 00000000000..7cc8058e77f --- /dev/null +++ b/pkg/reconciler/containersource/containersource.go @@ -0,0 +1,311 @@ +/* +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 containersource + +import ( + "context" + "fmt" + "reflect" + "strings" + "time" + + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/equality" + "k8s.io/apimachinery/pkg/api/errors" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + appsv1informers "k8s.io/client-go/informers/apps/v1" + appsv1listers "k8s.io/client-go/listers/apps/v1" + "k8s.io/client-go/tools/cache" + + "github.com/knative/eventing/pkg/apis/sources/v1alpha1" + sourceinformers "github.com/knative/eventing/pkg/client/informers/externalversions/sources/v1alpha1" + listers "github.com/knative/eventing/pkg/client/listers/sources/v1alpha1" + "github.com/knative/eventing/pkg/duck" + "github.com/knative/eventing/pkg/reconciler" + "github.com/knative/eventing/pkg/reconciler/containersource/resources" + "github.com/knative/pkg/controller" + "github.com/knative/pkg/logging" + "go.uber.org/zap" +) + +const ( + // ReconcilerName is the name of the reconciler + ReconcilerName = "ContainerSources" + // controllerAgentName is the string used by this controller to identify + // itself when creating events. + controllerAgentName = "container-source-controller" + + // Name of the corev1.Events emitted from the reconciliation process + sourceReconciled = "ContainerSourceReconciled" + sourceUpdateStatusFailed = "ContainerSourceUpdateStatusFailed" +) + +type Reconciler struct { + *reconciler.Base + + // listers index properties about resources + containerSourceLister listers.ContainerSourceLister + deploymentLister appsv1listers.DeploymentLister +} + +// 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, + containerSourceInformer sourceinformers.ContainerSourceInformer, + deploymentInformer appsv1informers.DeploymentInformer, +) *controller.Impl { + r := &Reconciler{ + Base: reconciler.NewBase(opt, controllerAgentName), + containerSourceLister: containerSourceInformer.Lister(), + deploymentLister: deploymentInformer.Lister(), + } + impl := controller.NewImpl(r, r.Logger, ReconcilerName, reconciler.MustNewStatsReporter(ReconcilerName, r.Logger)) + + r.Logger.Info("Setting up event handlers") + containerSourceInformer.Informer().AddEventHandler(reconciler.Handler(impl.Enqueue)) + + deploymentInformer.Informer().AddEventHandler(cache.FilteringResourceEventHandler{ + FilterFunc: controller.Filter(v1alpha1.SchemeGroupVersion.WithKind("ContainerSource")), + Handler: reconciler.Handler(impl.EnqueueControllerOf), + }) + + return impl +} + +// Reconcile compares the actual state with the desired, and attempts to +// converge the two. It then updates the Status block of the CronJobSource +// 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 + } + + // Get the CronJobSource resource with this namespace/name + original, err := r.containerSourceLister.ContainerSources(namespace).Get(name) + if apierrors.IsNotFound(err) { + // The resource may no longer exist, in which case we stop processing. + logging.FromContext(ctx).Error("ContainerSource key in work queue no longer exists", zap.Any("key", key)) + return nil + } else if err != nil { + return err + } + + // Don't modify the informers copy + source := original.DeepCopy() + + // Reconcile this copy of the ContainerSource and then write back any status + // updates regardless of whether the reconcile error out. + err = r.reconcile(ctx, source) + if err != nil { + logging.FromContext(ctx).Warn("Error reconciling ContainerSource", zap.Error(err)) + } else { + logging.FromContext(ctx).Debug("ContainerSource reconciled") + r.Recorder.Eventf(source, corev1.EventTypeNormal, sourceReconciled, `ContainerSource reconciled: "%s/%s"`, source.Namespace, source.Name) + } + + if _, updateStatusErr := r.updateStatus(ctx, source.DeepCopy()); updateStatusErr != nil { + logging.FromContext(ctx).Warn("Failed to update the ContainerSource", zap.Error(err)) + r.Recorder.Eventf(source, corev1.EventTypeWarning, sourceUpdateStatusFailed, "Failed to update ContainerSource's status: %v", err) + return updateStatusErr + } + + // Requeue if the resource is not ready: + return err +} + +func (r *Reconciler) reconcile(ctx context.Context, source *v1alpha1.ContainerSource) error { + // No need to reconcile if the source has been marked for deletion. + if source.DeletionTimestamp != nil { + return nil + } + + source.Status.InitializeConditions() + + annotations := make(map[string]string) + // Then wire through any annotations / labels from the Source + if source.ObjectMeta.Annotations != nil { + for k, v := range source.ObjectMeta.Annotations { + annotations[k] = v + } + } + labels := make(map[string]string) + if source.ObjectMeta.Labels != nil { + for k, v := range source.ObjectMeta.Labels { + labels[k] = v + } + } + + args := &resources.ContainerArguments{ + Source: source, + Name: source.Name, + Namespace: source.Namespace, + Image: source.Spec.Image, + Args: source.Spec.Args, + Env: source.Spec.Env, + ServiceAccountName: source.Spec.ServiceAccountName, + Annotations: annotations, + Labels: labels, + } + + err := r.setSinkURIArg(ctx, source, args) + if err != nil { + r.Recorder.Eventf(source, corev1.EventTypeWarning, "SetSinkURIFailed", "Failed to set Sink URI: %v", err) + return err + } + + deploy, err := r.getDeployment(ctx, source) + if err != nil { + if errors.IsNotFound(err) { + deploy, err = r.createDeployment(ctx, source, nil, args) + if err != nil { + r.markDeployingAndRecordEvent(source, corev1.EventTypeWarning, "DeploymentCreateFailed", "Could not create deployment: %v", err) + return err + } + r.markDeployingAndRecordEvent(source, corev1.EventTypeNormal, "DeploymentCreated", "Created deployment %q", deploy.Name) + // Since the Deployment has just been created, there's nothing more + // to do until it gets a status. This ContainerSource will be reconciled + // again when the Deployment is updated. + return nil + } + // Something unexpected happened getting the deployment. + r.markDeployingAndRecordEvent(source, corev1.EventTypeWarning, "DeploymentGetFailed", "Error getting deployment: %v", err) + return err + } + + // Update Deployment spec if it's changed + expected := resources.MakeDeployment(nil, args) + // Since the Deployment spec has fields defaulted by the webhook, it won't + // be equal to expected. Use DeepDerivative to compare only the fields that + // are set in expected. + if !equality.Semantic.DeepDerivative(expected.Spec, deploy.Spec) { + deploy.Spec = expected.Spec + deploy, err := r.KubeClientSet.AppsV1().Deployments(deploy.Namespace).Update(deploy) + if err != nil { + r.markDeployingAndRecordEvent(source, corev1.EventTypeWarning, "DeploymentUpdateFailed", "Failed to update deployment %q: %v", deploy.Name, err) + } else { + r.markDeployingAndRecordEvent(source, corev1.EventTypeNormal, "DeploymentUpdated", "Updated deployment %q", deploy.Name) + } + // Return after this update or error and reconcile again + return err + } + + // Update source status + if deploy.Status.ReadyReplicas > 0 && !source.Status.IsDeployed() { + source.Status.MarkDeployed() + r.Recorder.Eventf(source, corev1.EventTypeNormal, "DeploymentReady", "Deployment %q has %d ready replicas", deploy.Name, deploy.Status.ReadyReplicas) + } + + return nil +} + +// setSinkURIArg attempts to get the sink URI from the sink reference and +// set it in the source status. On failure, the source's Sink condition is +// updated to reflect the error. +// If an error is returned from this function, the caller should also record +// an Event containing the error string. +func (r *Reconciler) setSinkURIArg(ctx context.Context, source *v1alpha1.ContainerSource, args *resources.ContainerArguments) error { + if uri, ok := sinkArg(source); ok { + args.SinkInArgs = true + source.Status.MarkSink(uri) + return nil + } + + if source.Spec.Sink == nil { + source.Status.MarkNoSink("Missing", "Sink missing from spec") + return fmt.Errorf("Sink missing from spec") + } + + uri, err := duck.GetSinkURI(ctx, r.DynamicClientSet, source.Spec.Sink, source.Namespace) + if err != nil { + source.Status.MarkNoSink("NotFound", `Couldn't get Sink URI from "%s/%s": %v"`, source.Spec.Sink.Namespace, source.Spec.Sink.Name, err) + return err + } + source.Status.MarkSink(uri) + args.Sink = uri + + return nil +} + +func sinkArg(source *v1alpha1.ContainerSource) (string, bool) { + for _, a := range source.Spec.Args { + if strings.HasPrefix(a, "--sink=") { + return strings.Replace(a, "--sink=", "", -1), true + } + } + return "", false +} + +func (r *Reconciler) getDeployment(ctx context.Context, source *v1alpha1.ContainerSource) (*appsv1.Deployment, error) { + dl, err := r.KubeClientSet.AppsV1().Deployments(source.Namespace).List(metav1.ListOptions{}) + if err != nil { + r.Logger.Errorf("Unable to list deployments: %v", zap.Error(err)) + return nil, err + } + for _, c := range dl.Items { + if metav1.IsControlledBy(&c, source) { + return &c, nil + } + } + return nil, errors.NewNotFound(schema.GroupResource{}, "") +} + +func (r *Reconciler) createDeployment(ctx context.Context, source *v1alpha1.ContainerSource, org *appsv1.Deployment, args *resources.ContainerArguments) (*appsv1.Deployment, error) { + deployment := resources.MakeDeployment(org, args) + return r.KubeClientSet.AppsV1().Deployments(source.Namespace).Create(deployment) +} + +func (r *Reconciler) markDeployingAndRecordEvent(source *v1alpha1.ContainerSource, evType string, reason string, messageFmt string, args ...interface{}) { + r.Recorder.Eventf(source, evType, reason, messageFmt, args...) + source.Status.MarkDeploying(reason, messageFmt, args...) +} + +func (r *Reconciler) updateStatus(ctx context.Context, desired *v1alpha1.ContainerSource) (*v1alpha1.ContainerSource, error) { + source, err := r.containerSourceLister.ContainerSources(desired.Namespace).Get(desired.Name) + if err != nil { + return nil, err + } + + // If there's nothing to update, just return. + if reflect.DeepEqual(source.Status, desired.Status) { + return source, nil + } + + becomesReady := desired.Status.IsReady() && !source.Status.IsReady() + + // Don't modify the informers copy. + existing := source.DeepCopy() + existing.Status = desired.Status + + cj, err := r.EventingClientSet.SourcesV1alpha1().ContainerSources(desired.Namespace).UpdateStatus(existing) + if err == nil && becomesReady { + duration := time.Since(cj.ObjectMeta.CreationTimestamp.Time) + r.Logger.Infof("ContainerSource %q became ready after %v", source.Name, duration) + //r.StatsReporter.ReportServiceReady(subscription.Namespace, subscription.Name, duration) // TODO: stats + } + + return cj, err +} diff --git a/pkg/reconciler/containersource/containersource_test.go b/pkg/reconciler/containersource/containersource_test.go new file mode 100644 index 00000000000..64d0f3a28a2 --- /dev/null +++ b/pkg/reconciler/containersource/containersource_test.go @@ -0,0 +1,642 @@ +/* +Copyright 2019 The Knative Authors + +Licensed under the Apache License, Veroute.on 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT 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 containersource + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "testing" + + "github.com/google/go-cmp/cmp" + sourcesv1alpha1 "github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1" + controllertesting "github.com/knative/eventing-sources/pkg/controller/testing" + "github.com/knative/eventing-sources/pkg/reconciler/containersource/resources" + duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" + appsv1 "k8s.io/api/apps/v1" + 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/client-go/kubernetes/scheme" + "k8s.io/client-go/tools/record" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var ( + trueVal = true + targetURI = "http://addressable.sink.svc.cluster.local/" +) + +const ( + image = "github.com/knative/test/image" + containerSourceName = "testcontainersource" + testNS = "testnamespace" + containerSourceUID = "2a2208d1-ce67-11e8-b3a3-42010a8a00af" + deployGeneratedName = "" //sad trombone + + addressableDNS = "addressable.sink.svc.cluster.local" + + addressableName = "testsink" + addressableKind = "Sink" + addressableAPIVersion = "duck.knative.dev/v1alpha1" + + unaddressableName = "testunaddressable" + unaddressableKind = "KResource" + unaddressableAPIVersion = "duck.knative.dev/v1alpha1" + + sinkServiceName = "testsinkservice" + sinkServiceKind = "Service" + sinkServiceAPIVersion = "v1" +) + +func init() { + // Add types to scheme + sourcesv1alpha1.SchemeBuilder.AddToScheme(scheme.Scheme) + duckv1alpha1.AddToScheme(scheme.Scheme) +} + +var testCases = []controllertesting.TestCase{ + { + Name: "non existent key", + Reconciles: &sourcesv1alpha1.ContainerSource{}, + ReconcileKey: "non-existent-test-ns/non-existent-test-key", + WantErr: false, + }, { + Name: "valid containersource, but sink does not exist", + Reconciles: &sourcesv1alpha1.ContainerSource{}, + InitialState: []runtime.Object{ + getContainerSource(), + }, + ReconcileKey: fmt.Sprintf("%s/%s", testNS, containerSourceName), + WantErrMsg: `sinks.duck.knative.dev "testsink" not found`, + }, { + Name: "valid containersource, but sink is not addressable", + Reconciles: &sourcesv1alpha1.ContainerSource{}, + InitialState: []runtime.Object{ + getContainerSourceUnaddressable(), + getAddressableNoStatus(), + }, + ReconcileKey: fmt.Sprintf("%s/%s", testNS, containerSourceName), + Scheme: scheme.Scheme, + WantErrMsg: `sink "testnamespace/testunaddressable" (duck.knative.dev/v1alpha1, Kind=KResource) does not contain address`, + }, { + Name: "valid containersource, sink is addressable", + Reconciles: &sourcesv1alpha1.ContainerSource{}, + InitialState: []runtime.Object{ + getContainerSource(), + getAddressable(), + }, + ReconcileKey: fmt.Sprintf("%s/%s", testNS, containerSourceName), + Scheme: scheme.Scheme, + WantPresent: []runtime.Object{ + func() runtime.Object { + s := getContainerSource() + s.Status.InitializeConditions() + s.Status.MarkDeploying("DeploymentCreated", "Created deployment %q", deployGeneratedName) + s.Status.MarkSink(targetURI) + return s + }(), + }, + IgnoreTimes: true, + }, { + Name: "valid containersource, sink is addressable, fields filled in", + Reconciles: &sourcesv1alpha1.ContainerSource{}, + InitialState: []runtime.Object{ + getContainerSourceFilledIn(), + getAddressable(), + }, + ReconcileKey: fmt.Sprintf("%s/%s", testNS, containerSourceName), + Scheme: scheme.Scheme, + WantPresent: []runtime.Object{ + getDeployment(getContainerSourceFilledIn()), + }, + IgnoreTimes: true, + }, { + Name: "valid containersource, sink is Addressable but sink is nil", + Reconciles: &sourcesv1alpha1.ContainerSource{}, + InitialState: []runtime.Object{ + getContainerSource(), + getAddressableNilAddress(), + }, + ReconcileKey: fmt.Sprintf("%s/%s", testNS, containerSourceName), + Scheme: scheme.Scheme, + WantPresent: []runtime.Object{ + func() runtime.Object { + s := getContainerSource() + s.Status.InitializeConditions() + s.Status.MarkNoSink("NotFound", `Couldn't get Sink URI from "/testsink": sink "testnamespace/testsink" (duck.knative.dev/v1alpha1, Kind=Sink) does not contain address"`) + return s + }(), + }, + IgnoreTimes: true, + WantErrMsg: `sink "testnamespace/testsink" (duck.knative.dev/v1alpha1, Kind=Sink) does not contain address`, + }, { + Name: "invalid containersource, sink is nil", + Reconciles: &sourcesv1alpha1.ContainerSource{}, + InitialState: []runtime.Object{ + func() runtime.Object { + s := getContainerSource() + s.Spec.Sink = nil + return s + }(), + }, + ReconcileKey: fmt.Sprintf("%s/%s", testNS, containerSourceName), + Scheme: scheme.Scheme, + WantPresent: []runtime.Object{ + func() runtime.Object { + s := getContainerSource() + s.Spec.Sink = nil + s.Status.InitializeConditions() + s.Status.MarkNoSink("Missing", "Sink missing from spec") + return s + }(), + }, + IgnoreTimes: true, + WantErrMsg: `Sink missing from spec`, + }, { + Name: "valid containersource, sink is provided", + Reconciles: &sourcesv1alpha1.ContainerSource{}, + InitialState: []runtime.Object{ + func() runtime.Object { + s := getContainerSource() + s.Spec.Sink = nil + s.Spec.Args = append(s.Spec.Args, fmt.Sprintf("--sink=%s", targetURI)) + return s + }(), + }, + ReconcileKey: fmt.Sprintf("%s/%s", testNS, containerSourceName), + Scheme: scheme.Scheme, + WantPresent: []runtime.Object{ + func() runtime.Object { + s := getContainerSource() + s.Spec.Sink = nil + s.Spec.Args = append(s.Spec.Args, fmt.Sprintf("--sink=%s", targetURI)) + s.Status.InitializeConditions() + s.Status.MarkDeploying("DeploymentCreated", "Created deployment %q", deployGeneratedName) + s.Status.MarkSink(targetURI) + return s + }(), + }, + IgnoreTimes: true, + }, { + Name: "valid containersource, labels and annotations given", + Reconciles: &sourcesv1alpha1.ContainerSource{}, + InitialState: []runtime.Object{ + func() runtime.Object { + s := getContainerSource() + s.Spec.Sink = nil + s.Spec.Args = append(s.Spec.Args, fmt.Sprintf("--sink=%s", targetURI)) + s.ObjectMeta.Annotations = map[string]string{"annotation": "solid"} + s.ObjectMeta.Labels = map[string]string{"label": "soliderer"} + return s + }(), + }, + ReconcileKey: fmt.Sprintf("%s/%s", testNS, containerSourceName), + Scheme: scheme.Scheme, + WantPresent: []runtime.Object{ + func() runtime.Object { + s := getContainerSource() + s.Spec.Sink = nil + s.Spec.Args = append(s.Spec.Args, fmt.Sprintf("--sink=%s", targetURI)) + s.Status.InitializeConditions() + s.Status.MarkDeploying("DeploymentCreated", "Created deployment %q", deployGeneratedName) + s.Status.MarkSink(targetURI) + s.ObjectMeta.Annotations = map[string]string{"annotation": "solid"} + s.ObjectMeta.Labels = map[string]string{"label": "soliderer"} + return s + }(), + }, + IgnoreTimes: true, + }, { + Name: "valid containersource, sink, and deployment", + Reconciles: &sourcesv1alpha1.ContainerSource{}, + InitialState: []runtime.Object{ + func() runtime.Object { + s := getContainerSource() + s.UID = containerSourceUID + return s + }(), + func() runtime.Object { + // TODO(n3wscott): this is very strange, I was not able to get + // the fake client to return the resources.MakeDeployment version + // back in the list call. I might have missed setting some special + // metadata? Converting an unstructured and setting the fields + // I care about did work. + u := &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "namespace": testNS, + "name": containerSourceName + "-abc", + }, + }, + } + u.SetOwnerReferences(getOwnerReferences()) + + d := &appsv1.Deployment{} + d.Status.ReadyReplicas = 1 + j, _ := u.MarshalJSON() + json.Unmarshal(j, d) + + d1 := resources.MakeDeployment(nil, &resources.ContainerArguments{ + Name: containerSourceName, + Sink: "http://" + addressableDNS + "/", + Image: image, + }) + d.Spec = d1.Spec + return d + }(), + getAddressable(), + }, + ReconcileKey: fmt.Sprintf("%s/%s", testNS, containerSourceName), + Scheme: scheme.Scheme, + WantPresent: []runtime.Object{ + func() runtime.Object { + s := getContainerSource() + s.UID = containerSourceUID + s.Status.InitializeConditions() + s.Status.MarkDeployed() + s.Status.MarkSink(targetURI) + return s + }(), + }, + IgnoreTimes: true, + }, { + Name: "valid containersource, sink, but deployment needs update", + Reconciles: &sourcesv1alpha1.ContainerSource{}, + InitialState: []runtime.Object{ + func() runtime.Object { + s := getContainerSource() + s.UID = containerSourceUID + return s + }(), + func() runtime.Object { + // TODO(n3wscott): this is very strange, I was not able to get + // the fake client to return the resources.MakeDeployment version + // back in the list call. I might have missed setting some special + // metadata? Converting an unstructured and setting the fields + // I care about did work. + u := &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{ + "namespace": testNS, + "name": containerSourceName + "-abc", + }, + }, + } + u.SetOwnerReferences(getOwnerReferences()) + + d := &appsv1.Deployment{} + d.Status.ReadyReplicas = 1 + j, _ := u.MarshalJSON() + json.Unmarshal(j, d) + + d1 := resources.MakeDeployment(nil, &resources.ContainerArguments{ + Name: containerSourceName, + Sink: "http://old-" + addressableDNS + "/", + Image: image, + }) + d.Spec = d1.Spec + return d + }(), + getAddressable(), + }, + ReconcileKey: fmt.Sprintf("%s/%s", testNS, containerSourceName), + Scheme: scheme.Scheme, + WantPresent: []runtime.Object{ + func() runtime.Object { + s := getContainerSource() + s.UID = containerSourceUID + s.Status.InitializeConditions() + s.Status.MarkDeploying("DeploymentUpdated", "Updated deployment %q", containerSourceName+"-abc") + s.Status.MarkSink(targetURI) + return s + }(), + }, + IgnoreTimes: true, + }, { + Name: "Error for create deployment", + Reconciles: &sourcesv1alpha1.ContainerSource{}, + InitialState: []runtime.Object{ + func() runtime.Object { + s := getContainerSource() + s.UID = containerSourceUID + return s + }(), + getAddressable(), + }, + ReconcileKey: fmt.Sprintf("%s/%s", testNS, containerSourceName), + Scheme: scheme.Scheme, + Mocks: controllertesting.Mocks{ + MockCreates: []controllertesting.MockCreate{ + func(_ client.Client, _ context.Context, _ runtime.Object) (controllertesting.MockHandled, error) { + return controllertesting.Handled, errors.New("force an error into client create") + }, + }, + }, + IgnoreTimes: true, + WantErrMsg: `force an error into client create`, + }, { + Name: "Error for get source, other than not found", + Reconciles: &sourcesv1alpha1.ContainerSource{}, + InitialState: []runtime.Object{ + func() runtime.Object { + s := getContainerSource() + s.UID = containerSourceUID + return s + }(), + getAddressable(), + }, + ReconcileKey: fmt.Sprintf("%s/%s", testNS, containerSourceName), + Scheme: scheme.Scheme, + Mocks: controllertesting.Mocks{ + MockLists: []controllertesting.MockList{ + func(_ client.Client, _ context.Context, _ *client.ListOptions, _ runtime.Object) (controllertesting.MockHandled, error) { + return controllertesting.Handled, errors.New("force an error into client list") + }, + }, + }, + IgnoreTimes: true, + WantErrMsg: `force an error into client list`, + }, + /* TODO: support k8s service { + Name: "valid containersource, sink is a k8s service", + Reconciles: &sourcesv1alpha1.ContainerSource{}, + InitialState: []runtime.Object{ + getContainerSourceSinkService(), + }, + ReconcileKey: fmt.Sprintf("%s/%s", testNS, containerSourceName), + Scheme: scheme.Scheme, + Objects: []runtime.Object{ + // addressable + &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": sinkServiceAPIVersion, + "kind": sinkServiceKind, + "metadata": map[string]interface{}{ + "namespace": testNS, + "name": sinkServiceName, + }, + }}, + }, + },*/ +} + +func TestAllCases(t *testing.T) { + recorder := record.NewBroadcaster().NewRecorder(scheme.Scheme, corev1.EventSource{Component: controllerAgentName}) + + for _, tc := range testCases { + c := tc.GetClient() + + r := &reconciler{ + scheme: tc.Scheme, + recorder: recorder, + } + r.InjectClient(c) + t.Run(tc.Name, tc.Runner(t, r, c)) + } +} + +func getContainerSource() *sourcesv1alpha1.ContainerSource { + obj := &sourcesv1alpha1.ContainerSource{ + TypeMeta: containerSourceType(), + ObjectMeta: om(testNS, containerSourceName), + Spec: sourcesv1alpha1.ContainerSourceSpec{ + Image: image, + Args: []string(nil), + Sink: &corev1.ObjectReference{ + Name: addressableName, + Kind: addressableKind, + APIVersion: addressableAPIVersion, + }, + }, + } + // selflink is not filled in when we create the object, so clear it + obj.ObjectMeta.SelfLink = "" + return obj +} + +func getContainerSourceFilledIn() *sourcesv1alpha1.ContainerSource { + obj := getContainerSource() + obj.ObjectMeta.UID = containerSourceUID + obj.Spec.Args = []string{"--foo", "bar"} + obj.Spec.Env = []corev1.EnvVar{{Name: "FOO", Value: "bar"}} + obj.Spec.ServiceAccountName = "foo" + return obj +} + +func getContainerSourceSinkService() *sourcesv1alpha1.ContainerSource { + obj := &sourcesv1alpha1.ContainerSource{ + TypeMeta: containerSourceType(), + ObjectMeta: om(testNS, containerSourceName), + Spec: sourcesv1alpha1.ContainerSourceSpec{ + Image: image, + Args: []string(nil), + Sink: &corev1.ObjectReference{ + Name: sinkServiceName, + Kind: sinkServiceKind, + APIVersion: sinkServiceAPIVersion, + }, + }, + } + // selflink is not filled in when we create the object, so clear it + obj.ObjectMeta.SelfLink = "" + return obj +} + +func getContainerSourceUnaddressable() *sourcesv1alpha1.ContainerSource { + obj := &sourcesv1alpha1.ContainerSource{ + TypeMeta: containerSourceType(), + ObjectMeta: om(testNS, containerSourceName), + Spec: sourcesv1alpha1.ContainerSourceSpec{ + Image: image, + Args: []string{}, + Sink: &corev1.ObjectReference{ + Name: unaddressableName, + Kind: unaddressableKind, + APIVersion: unaddressableAPIVersion, + }, + }, + } + // selflink is not filled in when we create the object, so clear it + obj.ObjectMeta.SelfLink = "" + return obj +} + +func getAddressable() *unstructured.Unstructured { + return &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": addressableAPIVersion, + "kind": addressableKind, + "metadata": map[string]interface{}{ + "namespace": testNS, + "name": addressableName, + }, + "status": map[string]interface{}{ + "address": map[string]interface{}{ + "hostname": addressableDNS, + }, + }, + }, + } +} + +func getAddressableNoStatus() *unstructured.Unstructured { + return &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": unaddressableAPIVersion, + "kind": unaddressableKind, + "metadata": map[string]interface{}{ + "namespace": testNS, + "name": unaddressableName, + }, + }, + } +} + +func getAddressableNilAddress() *unstructured.Unstructured { + return &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": addressableAPIVersion, + "kind": addressableKind, + "metadata": map[string]interface{}{ + "namespace": testNS, + "name": addressableName, + }, + "status": map[string]interface{}{ + "address": map[string]interface{}(nil), + }, + }, + } +} + +func getDeployment(source *sourcesv1alpha1.ContainerSource) *appsv1.Deployment { + addressableURI := fmt.Sprintf("http://%s/", addressableDNS) + args := append(source.Spec.Args, fmt.Sprintf("--sink=%s", addressableURI)) + env := append(source.Spec.Env, corev1.EnvVar{Name: "SINK", Value: addressableURI}) + return &appsv1.Deployment{ + TypeMeta: deploymentType(), + ObjectMeta: metav1.ObjectMeta{ + GenerateName: fmt.Sprintf("%s-", source.Name), + Namespace: source.Namespace, + OwnerReferences: getOwnerReferences(), + }, + Spec: appsv1.DeploymentSpec{ + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "eventing.knative.dev/source": source.Name, + }, + }, + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + "sidecar.istio.io/inject": "true", + }, + Labels: map[string]string{ + "eventing.knative.dev/source": source.Name, + }, + }, + Spec: corev1.PodSpec{ + Containers: []corev1.Container{{ + Name: "source", + Image: source.Spec.Image, + Args: args, + Env: env, + ImagePullPolicy: corev1.PullIfNotPresent, + }}, + ServiceAccountName: source.Spec.ServiceAccountName, + }, + }, + }, + } +} + +func containerSourceType() metav1.TypeMeta { + return metav1.TypeMeta{ + APIVersion: sourcesv1alpha1.SchemeGroupVersion.String(), + Kind: "ContainerSource", + } +} + +func deploymentType() metav1.TypeMeta { + return metav1.TypeMeta{ + APIVersion: appsv1.SchemeGroupVersion.String(), + Kind: "Deployment", + } +} + +func om(namespace, name string) metav1.ObjectMeta { + return metav1.ObjectMeta{ + Namespace: namespace, + Name: name, + SelfLink: fmt.Sprintf("/apis/eventing/sources/v1alpha1/namespaces/%s/object/%s", namespace, name), + } +} + +func getOwnerReferences() []metav1.OwnerReference { + return []metav1.OwnerReference{{ + APIVersion: sourcesv1alpha1.SchemeGroupVersion.String(), + Kind: "ContainerSource", + Name: containerSourceName, + Controller: &trueVal, + BlockOwnerDeletion: &trueVal, + UID: containerSourceUID, + }} +} + +// Direct Unit tests. + +func TestObjectNotContainerSource(t *testing.T) { + r := reconciler{} + obj := &corev1.ObjectReference{ + Name: unaddressableName, + Kind: unaddressableKind, + APIVersion: unaddressableAPIVersion, + } + + got := obj.DeepCopy() + gotErr := r.Reconcile(context.TODO(), got) + var want runtime.Object = obj + if diff := cmp.Diff(want, got); diff != "" { + t.Errorf("unexpected returned object (-want, +got) = %v", diff) + } + if gotErr != nil { + t.Errorf("unexpected returned error %v", gotErr) + } +} + +func TestObjectHasDeleteTimestamp(t *testing.T) { + r := reconciler{} + obj := getContainerSource() + + now := metav1.Now() + obj.DeletionTimestamp = &now + got := obj.DeepCopy() + gotErr := r.Reconcile(context.TODO(), got) + var want runtime.Object = obj + if diff := cmp.Diff(want, got); diff != "" { + t.Errorf("unexpected returned object (-want, +got) = %v", diff) + } + if gotErr != nil { + t.Errorf("unexpected returned error %v", gotErr) + } +} diff --git a/pkg/reconciler/containersource/doc.go b/pkg/reconciler/containersource/doc.go new file mode 100644 index 00000000000..fa81f4b7843 --- /dev/null +++ b/pkg/reconciler/containersource/doc.go @@ -0,0 +1,18 @@ +/* +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 containersource implements the ContainerSource controller. +package containersource diff --git a/pkg/reconciler/containersource/resources/arguments.go b/pkg/reconciler/containersource/resources/arguments.go new file mode 100644 index 00000000000..37fc1aef7ef --- /dev/null +++ b/pkg/reconciler/containersource/resources/arguments.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 resources + +import ( + "github.com/knative/eventing/pkg/apis/sources/v1alpha1" + corev1 "k8s.io/api/core/v1" +) + +type ContainerArguments struct { + Source *v1alpha1.ContainerSource + Name string + Namespace string + Image string + Args []string + Env []corev1.EnvVar + ServiceAccountName string + SinkInArgs bool + Sink string + Annotations map[string]string + Labels map[string]string +} diff --git a/pkg/reconciler/containersource/resources/deployment.go b/pkg/reconciler/containersource/resources/deployment.go new file mode 100644 index 00000000000..7dffe89857f --- /dev/null +++ b/pkg/reconciler/containersource/resources/deployment.go @@ -0,0 +1,119 @@ +/* +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 resources + +import ( + "fmt" + "github.com/knative/pkg/kmeta" + "strings" + + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +const sourceLabelKey = "eventing.knative.dev/source" + +func MakeDeployment(org *appsv1.Deployment, args *ContainerArguments) *appsv1.Deployment { + + containerArgs := []string(nil) + if args != nil { + containerArgs = args.Args + } + // if sink is already in the provided args.Args, don't attempt to add + if !args.SinkInArgs { + remote := fmt.Sprintf("--sink=%s", args.Sink) + containerArgs = append(containerArgs, remote) + } + + env := append(args.Env, corev1.EnvVar{Name: "SINK", Value: sinkArg(args)}) + + deploy := &appsv1.Deployment{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "apps/v1", + Kind: "Deployment", + }, + ObjectMeta: metav1.ObjectMeta{ + GenerateName: args.Name + "-", + Namespace: args.Namespace, + OwnerReferences: []metav1.OwnerReference{ + *kmeta.NewControllerRef(args.Source), + }, + }, + Spec: appsv1.DeploymentSpec{ + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + sourceLabelKey: args.Name, + }, + }, + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + "sidecar.istio.io/inject": "true", + }, + Labels: map[string]string{ + sourceLabelKey: args.Name, + }, + }, + Spec: corev1.PodSpec{ + ServiceAccountName: args.ServiceAccountName, + Containers: []corev1.Container{ + { + Name: "source", + Image: args.Image, + Args: containerArgs, + Env: env, + ImagePullPolicy: corev1.PullIfNotPresent, + }, + }, + }, + }, + }, + } + + // Then wire through any annotations from the source. Not a bug by allowing + // the container to override Istio injection. + if args.Annotations != nil { + for k, v := range args.Annotations { + deploy.Spec.Template.ObjectMeta.Annotations[k] = v + } + } + + // Then wire through any labels from the source. Do not allow to override + // our source name. This seems like it would be way errorprone by allowing + // the matchlabels then to not match, or we'd have to force them to match, etc. + // just don't allow it. + if args.Labels != nil { + for k, v := range args.Labels { + if k != sourceLabelKey { + deploy.Spec.Template.ObjectMeta.Labels[k] = v + } + } + } + return deploy +} + +func sinkArg(args *ContainerArguments) string { + if args.SinkInArgs { + for _, a := range args.Args { + if strings.HasPrefix(a, "--sink=") { + return strings.Replace(a, "--sink=", "", -1) + } + } + } + return args.Sink +} diff --git a/pkg/reconciler/containersource/resources/deployment_test.go b/pkg/reconciler/containersource/resources/deployment_test.go new file mode 100644 index 00000000000..79c82cf6df4 --- /dev/null +++ b/pkg/reconciler/containersource/resources/deployment_test.go @@ -0,0 +1,292 @@ +/* +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 resources + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func TestMakeDeployment_sinkoverrideannotationlabelnotallowed(t *testing.T) { + got := MakeDeployment(nil, &ContainerArguments{ + Name: "test-name", + Namespace: "test-namespace", + Image: "test-image", + Args: []string{"--test1=args1", "--test2=args2"}, + Env: []corev1.EnvVar{{ + Name: "test1", + Value: "arg1", + }, { + Name: "test2", + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + Key: "test2-secret", + }, + }, + }}, + ServiceAccountName: "test-service-account", + SinkInArgs: false, + Sink: "test-sink", + Labels: map[string]string{ + "eventing.knative.dev/source": "not-allowed", + "anotherlabel": "extra-label", + }, + Annotations: map[string]string{ + "sidecar.istio.io/inject": "false", + "anotherannotation": "extra-annotation", + }, + }) + + want := &appsv1.Deployment{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "apps/v1", + Kind: "Deployment", + }, + ObjectMeta: metav1.ObjectMeta{ + GenerateName: "test-name-", + Namespace: "test-namespace", + }, + Spec: appsv1.DeploymentSpec{ + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "eventing.knative.dev/source": "test-name", + }, + }, + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + "sidecar.istio.io/inject": "false", + "anotherannotation": "extra-annotation", + }, + Labels: map[string]string{ + "eventing.knative.dev/source": "test-name", + "anotherlabel": "extra-label", + }, + }, + Spec: corev1.PodSpec{ + ServiceAccountName: "test-service-account", + Containers: []corev1.Container{ + { + Name: "source", + Image: "test-image", + Args: []string{ + "--test1=args1", + "--test2=args2", + "--sink=test-sink", + }, + Env: []corev1.EnvVar{ + { + Name: "test1", + Value: "arg1", + }, { + Name: "test2", + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + Key: "test2-secret", + }, + }, + }, { + Name: "SINK", + Value: "test-sink", + }}, + ImagePullPolicy: corev1.PullIfNotPresent, + }, + }, + }, + }, + }, + } + + if diff := cmp.Diff(want, got); diff != "" { + t.Errorf("unexpected deploy (-want, +got) = %v", diff) + } +} + +func TestMakeDeployment_sink(t *testing.T) { + got := MakeDeployment(nil, &ContainerArguments{ + Name: "test-name", + Namespace: "test-namespace", + Image: "test-image", + Args: []string{"--test1=args1", "--test2=args2"}, + Env: []corev1.EnvVar{{ + Name: "test1", + Value: "arg1", + }, { + Name: "test2", + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + Key: "test2-secret", + }, + }, + }}, + ServiceAccountName: "test-service-account", + SinkInArgs: false, + Sink: "test-sink", + }) + + want := &appsv1.Deployment{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "apps/v1", + Kind: "Deployment", + }, + ObjectMeta: metav1.ObjectMeta{ + GenerateName: "test-name-", + Namespace: "test-namespace", + }, + Spec: appsv1.DeploymentSpec{ + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "eventing.knative.dev/source": "test-name", + }, + }, + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + "sidecar.istio.io/inject": "true", + }, + Labels: map[string]string{ + "eventing.knative.dev/source": "test-name", + }, + }, + Spec: corev1.PodSpec{ + ServiceAccountName: "test-service-account", + Containers: []corev1.Container{ + { + Name: "source", + Image: "test-image", + Args: []string{ + "--test1=args1", + "--test2=args2", + "--sink=test-sink", + }, + Env: []corev1.EnvVar{ + { + Name: "test1", + Value: "arg1", + }, { + Name: "test2", + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + Key: "test2-secret", + }, + }, + }, { + Name: "SINK", + Value: "test-sink", + }}, + ImagePullPolicy: corev1.PullIfNotPresent, + }, + }, + }, + }, + }, + } + + if diff := cmp.Diff(want, got); diff != "" { + t.Errorf("unexpected deploy (-want, +got) = %v", diff) + } +} + +func TestMakeDeployment_sinkinargs(t *testing.T) { + got := MakeDeployment(nil, &ContainerArguments{ + Name: "test-name", + Namespace: "test-namespace", + Image: "test-image", + Args: []string{"--test1=args1", "--test2=args2", "--sink=test-sink"}, + Env: []corev1.EnvVar{{ + Name: "test1", + Value: "arg1", + }, { + Name: "test2", + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + Key: "test2-secret", + }, + }, + }}, + ServiceAccountName: "test-service-account", + SinkInArgs: true, + Labels: map[string]string{"eventing.knative.dev/source": "test-name"}, + Annotations: map[string]string{"sidecar.istio.io/inject": "true"}, + }) + + want := &appsv1.Deployment{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "apps/v1", + Kind: "Deployment", + }, + ObjectMeta: metav1.ObjectMeta{ + GenerateName: "test-name-", + Namespace: "test-namespace", + }, + Spec: appsv1.DeploymentSpec{ + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "eventing.knative.dev/source": "test-name", + }, + }, + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + "sidecar.istio.io/inject": "true", + }, + Labels: map[string]string{ + "eventing.knative.dev/source": "test-name", + }, + }, + Spec: corev1.PodSpec{ + ServiceAccountName: "test-service-account", + Containers: []corev1.Container{ + { + Name: "source", + Image: "test-image", + Args: []string{ + "--test1=args1", + "--test2=args2", + "--sink=test-sink", + }, + Env: []corev1.EnvVar{ + { + Name: "test1", + Value: "arg1", + }, { + Name: "test2", + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + Key: "test2-secret", + }, + }, + }, { + Name: "SINK", + Value: "test-sink", + }}, + ImagePullPolicy: corev1.PullIfNotPresent, + }, + }, + }, + }, + }, + } + + if diff := cmp.Diff(want, got); diff != "" { + t.Errorf("unexpected deploy (-want, +got) = %v", diff) + } +} diff --git a/pkg/reconciler/cronjobsource/cronjobsource.go b/pkg/reconciler/cronjobsource/cronjobsource.go index 488f144ca5b..9c678d26c04 100644 --- a/pkg/reconciler/cronjobsource/cronjobsource.go +++ b/pkg/reconciler/cronjobsource/cronjobsource.go @@ -28,7 +28,6 @@ import ( corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/equality" apierrors "k8s.io/apimachinery/pkg/api/errors" - apierrs "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" @@ -116,7 +115,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, key string) error { // Get the CronJobSource resource with this namespace/name original, err := r.cronjobLister.CronJobSources(namespace).Get(name) - if apierrs.IsNotFound(err) { + if apierrors.IsNotFound(err) { // The resource may no longer exist, in which case we stop processing. logging.FromContext(ctx).Error("CronJobSource key in work queue no longer exists", zap.Any("key", key)) return nil diff --git a/vendor/github.com/knative/eventing-sources/AUTHORS b/vendor/github.com/knative/eventing-sources/AUTHORS new file mode 100644 index 00000000000..9a8f2f769f4 --- /dev/null +++ b/vendor/github.com/knative/eventing-sources/AUTHORS @@ -0,0 +1,6 @@ +# This is the list of Knative authors for copyright purposes. +# +# This does not necessarily list everyone who has contributed code, since in +# some cases, their employer may be the copyright holder. To see the full list +# of contributors, see the revision history in source control. +Google LLC diff --git a/vendor/github.com/knative/eventing-sources/LICENSE b/vendor/github.com/knative/eventing-sources/LICENSE new file mode 100644 index 00000000000..261eeb9e9f8 --- /dev/null +++ b/vendor/github.com/knative/eventing-sources/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/knative/eventing-sources/pkg/apis/sources/v1alpha1/aws_sqs_types.go b/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/aws_sqs_types.go new file mode 100644 index 00000000000..1f93837ce19 --- /dev/null +++ b/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/aws_sqs_types.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 ( + "github.com/knative/pkg/apis/duck" + duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// AwsSqsSource is the Schema for the AWS SQS API +// +k8s:openapi-gen=true +// +kubebuilder:subresource:status +// +kubebuilder:categories=all,knative,eventing,sources +type AwsSqsSource struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec AwsSqsSourceSpec `json:"spec,omitempty"` + Status AwsSqsSourceStatus `json:"status,omitempty"` +} + +// Check that AwsSqsSource can be validated and can be defaulted. +var _ runtime.Object = (*AwsSqsSource)(nil) + +// Check that AwsSqsSource implements the Conditions duck type. +var _ = duck.VerifyType(&AwsSqsSource{}, &duckv1alpha1.Conditions{}) + +// AwsSqsSourceSpec defines the desired state of the source. +type AwsSqsSourceSpec struct { + // QueueURL of the SQS queue that we will poll from. + QueueURL string `json:"queueUrl"` + + // AwsCredsSecret is the credential to use to poll the AWS SQS + AwsCredsSecret corev1.SecretKeySelector `json:"awsCredsSecret,omitempty"` + + // Sink is a reference to an object that will resolve to a domain name to + // use as the sink. This is where events will be received. + // +optional + Sink *corev1.ObjectReference `json:"sink,omitempty"` + + // ServiceAccoutName is the name of the ServiceAccount that will be used to + // run the Receive Adapter Deployment. + ServiceAccountName string `json:"serviceAccountName,omitempty"` +} + +const ( + // AwsSqsSourceConditionReady has status True when the source is + // ready to send events. + AwsSqsSourceConditionReady = duckv1alpha1.ConditionReady + + // AwsSqsSourceConditionSinkProvided has status True when the + // AwsSqsSource has been configured with a sink target. + AwsSqsSourceConditionSinkProvided duckv1alpha1.ConditionType = "SinkProvided" + + // AwsSqsSourceConditionDeployed has status True when the + // AwsSqsSource has had it's receive adapter deployment created. + AwsSqsSourceConditionDeployed duckv1alpha1.ConditionType = "Deployed" +) + +var condSet = duckv1alpha1.NewLivingConditionSet( + AwsSqsSourceConditionReady, + AwsSqsSourceConditionSinkProvided, + AwsSqsSourceConditionDeployed) + +// AwsSqsSourceStatus defines the observed state of the source. +type AwsSqsSourceStatus struct { + // 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"` + + // SinkURI is the current active sink URI that has been configured for the source. + // +optional + SinkURI string `json:"sinkUri,omitempty"` +} + +// GetCondition returns the condition currently associated with the given type, or nil. +func (s *AwsSqsSourceStatus) GetCondition(t duckv1alpha1.ConditionType) *duckv1alpha1.Condition { + return condSet.Manage(s).GetCondition(t) +} + +// IsReady returns true if the resource is ready overall. +func (s *AwsSqsSourceStatus) IsReady() bool { + return condSet.Manage(s).IsHappy() +} + +// InitializeConditions sets relevant unset conditions to Unknown state. +func (s *AwsSqsSourceStatus) InitializeConditions() { + condSet.Manage(s).InitializeConditions() +} + +// MarkSink sets the condition that the source has a sink configured. +func (s *AwsSqsSourceStatus) MarkSink(uri string) { + s.SinkURI = uri + if len(uri) > 0 { + condSet.Manage(s).MarkTrue(AwsSqsSourceConditionSinkProvided) + } else { + condSet.Manage(s).MarkUnknown(AwsSqsSourceConditionSinkProvided, + "SinkEmpty", "Sink has resolved to empty.%s", "") + } +} + +// MarkNoSink sets the condition that the source does not have a sink configured. +func (s *AwsSqsSourceStatus) MarkNoSink(reason, messageFormat string, messageA ...interface{}) { + condSet.Manage(s).MarkFalse(AwsSqsSourceConditionSinkProvided, reason, messageFormat, messageA...) +} + +// MarkDeployed sets the condition that the source has been deployed. +func (s *AwsSqsSourceStatus) MarkDeployed() { + condSet.Manage(s).MarkTrue(AwsSqsSourceConditionDeployed) +} + +// MarkDeploying sets the condition that the source is deploying. +func (s *AwsSqsSourceStatus) MarkDeploying(reason, messageFormat string, messageA ...interface{}) { + condSet.Manage(s).MarkUnknown(AwsSqsSourceConditionDeployed, reason, messageFormat, messageA...) +} + +// MarkNotDeployed sets the condition that the source has not been deployed. +func (s *AwsSqsSourceStatus) MarkNotDeployed(reason, messageFormat string, messageA ...interface{}) { + condSet.Manage(s).MarkFalse(AwsSqsSourceConditionDeployed, reason, messageFormat, messageA...) +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// AwsSqsSourceList contains a list of AwsSqsSource +type AwsSqsSourceList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []AwsSqsSource `json:"items"` +} + +func init() { + SchemeBuilder.Register(&AwsSqsSource{}, &AwsSqsSourceList{}) +} diff --git a/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/containersource_types.go b/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/containersource_types.go new file mode 100644 index 00000000000..4492ca14690 --- /dev/null +++ b/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/containersource_types.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. +*/ + +package v1alpha1 + +import ( + "github.com/knative/pkg/apis/duck" + duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +// Check that ContainerSource can be validated and can be defaulted. +var _ runtime.Object = (*ContainerSource)(nil) + +// Check that ContainerSource implements the Conditions duck type. +var _ = duck.VerifyType(&ContainerSource{}, &duckv1alpha1.Conditions{}) + +// ContainerSourceSpec defines the desired state of ContainerSource +type ContainerSourceSpec struct { + // Image is the image to run inside of the container. + // +kubebuilder:validation:MinLength=1 + Image string `json:"image,omitempty"` + + // Args are passed to the ContainerSpec as they are. + Args []string `json:"args,omitempty"` + + // Env is the list of environment variables to set in the container. + // Cannot be updated. + // +optional + // +patchMergeKey=name + // +patchStrategy=merge + Env []corev1.EnvVar `json:"env,omitempty" patchStrategy:"merge" patchMergeKey:"name"` + + // ServiceAccountName is the name of the ServiceAccount to use to run this + // source. + // +optional + ServiceAccountName string `json:"serviceAccountName,omitempty"` + + // Sink is a reference to an object that will resolve to a domain name to use as the sink. + // +optional + Sink *corev1.ObjectReference `json:"sink,omitempty"` +} + +const ( + // ContainerSourceConditionReady has status True when the ContainerSource is ready to send events. + ContainerConditionReady = duckv1alpha1.ConditionReady + + // ContainerConditionSinkProvided has status True when the ContainerSource has been configured with a sink target. + ContainerConditionSinkProvided duckv1alpha1.ConditionType = "SinkProvided" + + // ContainerConditionDeployed has status True when the ContainerSource has had it's deployment created. + ContainerConditionDeployed duckv1alpha1.ConditionType = "Deployed" +) + +var containerCondSet = duckv1alpha1.NewLivingConditionSet( + ContainerConditionSinkProvided, + ContainerConditionDeployed) + +// ContainerSourceStatus defines the observed state of ContainerSource +type ContainerSourceStatus struct { + // 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"` + + // SinkURI is the current active sink URI that has been configured for the ContainerSource. + // +optional + SinkURI string `json:"sinkUri,omitempty"` +} + +// GetCondition returns the condition currently associated with the given type, or nil. +func (s *ContainerSourceStatus) GetCondition(t duckv1alpha1.ConditionType) *duckv1alpha1.Condition { + return containerCondSet.Manage(s).GetCondition(t) +} + +// IsReady returns true if the resource is ready overall. +func (s *ContainerSourceStatus) IsReady() bool { + return containerCondSet.Manage(s).IsHappy() +} + +// InitializeConditions sets relevant unset conditions to Unknown state. +func (s *ContainerSourceStatus) InitializeConditions() { + containerCondSet.Manage(s).InitializeConditions() +} + +// MarSink sets the condition that the source has a sink configured. +func (s *ContainerSourceStatus) MarkSink(uri string) { + s.SinkURI = uri + if len(uri) > 0 { + containerCondSet.Manage(s).MarkTrue(ContainerConditionSinkProvided) + } else { + containerCondSet.Manage(s).MarkUnknown(ContainerConditionSinkProvided, "SinkEmpty", "Sink has resolved to empty.%s", "") + } +} + +// MarkNoSink sets the condition that the source does not have a sink configured. +func (s *ContainerSourceStatus) MarkNoSink(reason, messageFormat string, messageA ...interface{}) { + containerCondSet.Manage(s).MarkFalse(ContainerConditionSinkProvided, reason, messageFormat, messageA...) +} + +// MarkDeployed sets the condition that the source has been deployed. +func (s *ContainerSourceStatus) MarkDeployed() { + containerCondSet.Manage(s).MarkTrue(ContainerConditionDeployed) +} + +// MarkDeploying sets the condition that the source is deploying. +func (s *ContainerSourceStatus) MarkDeploying(reason, messageFormat string, messageA ...interface{}) { + containerCondSet.Manage(s).MarkUnknown(ContainerConditionDeployed, reason, messageFormat, messageA...) +} + +// MarkNotDeployed sets the condition that the source has not been deployed. +func (s *ContainerSourceStatus) MarkNotDeployed(reason, messageFormat string, messageA ...interface{}) { + containerCondSet.Manage(s).MarkFalse(ContainerConditionDeployed, reason, messageFormat, messageA...) +} + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// ContainerSource is the Schema for the containersources API +// +k8s:openapi-gen=true +// +kubebuilder:subresource:status +// +kubebuilder:categories=all,knative,eventing,sources +type ContainerSource struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec ContainerSourceSpec `json:"spec,omitempty"` + Status ContainerSourceStatus `json:"status,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// ContainerSourceList contains a list of ContainerSource +type ContainerSourceList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []ContainerSource `json:"items"` +} + +func init() { + SchemeBuilder.Register(&ContainerSource{}, &ContainerSourceList{}) +} diff --git a/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/cron_job_types.go b/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/cron_job_types.go new file mode 100644 index 00000000000..aaeffc74e89 --- /dev/null +++ b/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/cron_job_types.go @@ -0,0 +1,164 @@ +/* +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/duck" + duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// CronJobSource is the Schema for the cronjobsources API. +// +k8s:openapi-gen=true +// +kubebuilder:subresource:status +// +kubebuilder:categories=all,knative,eventing,sources +type CronJobSource struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec CronJobSourceSpec `json:"spec,omitempty"` + Status CronJobSourceStatus `json:"status,omitempty"` +} + +// Check that CronJobSource can be validated and can be defaulted. +var _ runtime.Object = (*CronJobSource)(nil) + +// Check that CronJobSource implements the Conditions duck type. +var _ = duck.VerifyType(&CronJobSource{}, &duckv1alpha1.Conditions{}) + +// CronJobSourceSpec defines the desired state of the CronJobSource. +type CronJobSourceSpec struct { + + // Schedule is the cronjob schedule. + // +required + Schedule string `json:"schedule"` + + // Data is the data posted to the target function. + Data string `json:"data,omitempty"` + + // Sink is a reference to an object that will resolve to a domain name to use as the sink. + // +optional + Sink *corev1.ObjectReference `json:"sink,omitempty"` + + // ServiceAccoutName is the name of the ServiceAccount that will be used to run the Receive + // Adapter Deployment. + ServiceAccountName string `json:"serviceAccountName,omitempty"` +} + +const ( + // CronJobConditionReady has status True when the CronJobSource is ready to send events. + CronJobConditionReady = duckv1alpha1.ConditionReady + + // CronJobConditionValidSchedule has status True when the CronJobSource has been configured with a valid schedule. + CronJobConditionValidSchedule duckv1alpha1.ConditionType = "ValidSchedule" + + // CronJobConditionSinkProvided has status True when the CronJobSource has been configured with a sink target. + CronJobConditionSinkProvided duckv1alpha1.ConditionType = "SinkProvided" + + // CronJobConditionDeployed has status True when the CronJobSource has had it's receive adapter deployment created. + CronJobConditionDeployed duckv1alpha1.ConditionType = "Deployed" +) + +var cronJobSourceCondSet = duckv1alpha1.NewLivingConditionSet( + CronJobConditionValidSchedule, + CronJobConditionSinkProvided, + CronJobConditionDeployed) + +// CronJobSourceStatus defines the observed state of CronJobSource. +type CronJobSourceStatus struct { + // 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"` + + // SinkURI is the current active sink URI that has been configured for the CronJobSource. + // +optional + SinkURI string `json:"sinkUri,omitempty"` +} + +// GetCondition returns the condition currently associated with the given type, or nil. +func (s *CronJobSourceStatus) GetCondition(t duckv1alpha1.ConditionType) *duckv1alpha1.Condition { + return cronJobSourceCondSet.Manage(s).GetCondition(t) +} + +// IsReady returns true if the resource is ready overall. +func (s *CronJobSourceStatus) IsReady() bool { + return cronJobSourceCondSet.Manage(s).IsHappy() +} + +// InitializeConditions sets relevant unset conditions to Unknown state. +func (s *CronJobSourceStatus) InitializeConditions() { + cronJobSourceCondSet.Manage(s).InitializeConditions() +} + +// MarkSchedule sets the condition that the source has a valid schedule configured. +func (s *CronJobSourceStatus) MarkSchedule() { + cronJobSourceCondSet.Manage(s).MarkTrue(CronJobConditionValidSchedule) +} + +// MarkInvalidSchedule sets the condition that the source does not have a valid schedule configured. +func (s *CronJobSourceStatus) MarkInvalidSchedule(reason, messageFormat string, messageA ...interface{}) { + cronJobSourceCondSet.Manage(s).MarkFalse(CronJobConditionValidSchedule, reason, messageFormat, messageA...) +} + +// MarkSink sets the condition that the source has a sink configured. +func (s *CronJobSourceStatus) MarkSink(uri string) { + s.SinkURI = uri + if len(uri) > 0 { + cronJobSourceCondSet.Manage(s).MarkTrue(CronJobConditionSinkProvided) + } else { + cronJobSourceCondSet.Manage(s).MarkUnknown(CronJobConditionSinkProvided, "SinkEmpty", "Sink has resolved to empty.%s", "") + } +} + +// MarkNoSink sets the condition that the source does not have a sink configured. +func (s *CronJobSourceStatus) MarkNoSink(reason, messageFormat string, messageA ...interface{}) { + cronJobSourceCondSet.Manage(s).MarkFalse(CronJobConditionSinkProvided, reason, messageFormat, messageA...) +} + +// MarkDeployed sets the condition that the source has been deployed. +func (s *CronJobSourceStatus) MarkDeployed() { + cronJobSourceCondSet.Manage(s).MarkTrue(CronJobConditionDeployed) +} + +// MarkDeploying sets the condition that the source is deploying. +func (s *CronJobSourceStatus) MarkDeploying(reason, messageFormat string, messageA ...interface{}) { + cronJobSourceCondSet.Manage(s).MarkUnknown(CronJobConditionDeployed, reason, messageFormat, messageA...) +} + +// MarkNotDeployed sets the condition that the source has not been deployed. +func (s *CronJobSourceStatus) MarkNotDeployed(reason, messageFormat string, messageA ...interface{}) { + cronJobSourceCondSet.Manage(s).MarkFalse(CronJobConditionDeployed, reason, messageFormat, messageA...) +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// CronJobSourceList contains a list of CronJobSources. +type CronJobSourceList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []CronJobSource `json:"items"` +} + +func init() { + SchemeBuilder.Register(&CronJobSource{}, &CronJobSourceList{}) +} diff --git a/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/doc.go b/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/doc.go new file mode 100644 index 00000000000..258a98c9176 --- /dev/null +++ b/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/doc.go @@ -0,0 +1,23 @@ +/* +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 contains API Schema definitions for the sources v1alpha1 API group +// +k8s:openapi-gen=true +// +k8s:deepcopy-gen=package,register +// +k8s:conversion-gen=github.com/knative/eventing-sources/pkg/apis/sources +// +k8s:defaulter-gen=TypeMeta +// +groupName=sources.eventing.knative.dev +package v1alpha1 diff --git a/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/githubsource_types.go b/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/githubsource_types.go new file mode 100644 index 00000000000..808e0fc9542 --- /dev/null +++ b/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/githubsource_types.go @@ -0,0 +1,195 @@ +/* +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/duck" + duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +// Check that GitHubSource can be validated and can be defaulted. +var _ runtime.Object = (*GitHubSource)(nil) + +// Check that GitHubSource implements the Conditions duck type. +var _ = duck.VerifyType(&GitHubSource{}, &duckv1alpha1.Conditions{}) + +// GitHubSourceSpec defines the desired state of GitHubSource +// +kubebuilder:categories=all,knative,eventing,sources +type GitHubSourceSpec struct { + // ServiceAccountName holds the name of the Kubernetes service account + // as which the underlying K8s resources should be run. If unspecified + // this will default to the "default" service account for the namespace + // in which the GitHubSource exists. + // +optional + ServiceAccountName string `json:"serviceAccountName,omitempty"` + + // OwnerAndRepository is the GitHub owner/org and repository to + // receive events from. The repository may be left off to receive + // events from an entire organization. + // Examples: + // myuser/project + // myorganization + // +kubebuilder:validation:MinLength=1 + OwnerAndRepository string `json:"ownerAndRepository"` + + // EventType is the type of event to receive from GitHub. These + // correspond to the "Webhook event name" values listed at + // https://developer.github.com/v3/activity/events/types/ - ie + // "pull_request" + // +kubebuilder:validation:MinItems=1 + // +kubebuilder:validation:Enum=commit_comment,create,delete,deployment,deployment_status,fork,gollum,installation,integration_installation,issue_comment,issues,label,member,membership,milestone,organization,org_block,page_build,ping,project_card,project_column,project,public,pull_request,pull_request_review,pull_request_review_comment,push,release,repository,status,team,team_add,watch + EventTypes []string `json:"eventTypes"` + + // AccessToken is the Kubernetes secret containing the GitHub + // access token + AccessToken SecretValueFromSource `json:"accessToken"` + + // SecretToken is the Kubernetes secret containing the GitHub + // secret token + SecretToken SecretValueFromSource `json:"secretToken"` + + // Sink is a reference to an object that will resolve to a domain + // name to use as the sink. + // +optional + Sink *corev1.ObjectReference `json:"sink,omitempty"` + + // API URL if using github enterprise (default https://api.github.com) + // +optional + GitHubAPIURL string `json:"githubAPIURL,omitempty"` + + // Secure can be set to true to configure the webhook to use https. + // +optional + Secure bool `json:"secure,omitempty"` +} + +// SecretValueFromSource represents the source of a secret value +type SecretValueFromSource struct { + // The Secret key to select from. + SecretKeyRef *corev1.SecretKeySelector `json:"secretKeyRef,omitempty"` +} + +const ( + // GitHubSourceEventPrefix is what all GitHub event types get + // prefixed with when converting to CloudEvent EventType + GitHubSourceEventPrefix = "dev.knative.source.github" +) + +const ( + // GitHubSourceConditionReady has status True when the + // GitHubSource is ready to send events. + GitHubSourceConditionReady = duckv1alpha1.ConditionReady + + // GitHubSourceConditionSecretsProvided has status True when the + // GitHubSource has valid secret references + GitHubSourceConditionSecretsProvided duckv1alpha1.ConditionType = "SecretsProvided" + + // GitHubSourceConditionSinkProvided has status True when the + // GitHubSource has been configured with a sink target. + GitHubSourceConditionSinkProvided duckv1alpha1.ConditionType = "SinkProvided" +) + +var gitHubSourceCondSet = duckv1alpha1.NewLivingConditionSet( + GitHubSourceConditionSecretsProvided, + GitHubSourceConditionSinkProvided) + +// GitHubSourceStatus defines the observed state of GitHubSource +type GitHubSourceStatus struct { + // 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"` + + // WebhookIDKey is the ID of the webhook registered with GitHub + WebhookIDKey string `json:"webhookIDKey,omitempty"` + + // SinkURI is the current active sink URI that has been configured + // for the GitHubSource. + // +optional + SinkURI string `json:"sinkUri,omitempty"` +} + +// GetCondition returns the condition currently associated with the given type, or nil. +func (s *GitHubSourceStatus) GetCondition(t duckv1alpha1.ConditionType) *duckv1alpha1.Condition { + return gitHubSourceCondSet.Manage(s).GetCondition(t) +} + +// IsReady returns true if the resource is ready overall. +func (s *GitHubSourceStatus) IsReady() bool { + return gitHubSourceCondSet.Manage(s).IsHappy() +} + +// InitializeConditions sets relevant unset conditions to Unknown state. +func (s *GitHubSourceStatus) InitializeConditions() { + gitHubSourceCondSet.Manage(s).InitializeConditions() +} + +// MarkSecrets sets the condition that the source has a valid spec +func (s *GitHubSourceStatus) MarkSecrets() { + gitHubSourceCondSet.Manage(s).MarkTrue(GitHubSourceConditionSecretsProvided) +} + +// MarkNoSecrets sets the condition that the source does not have a valid spec +func (s *GitHubSourceStatus) MarkNoSecrets(reason, messageFormat string, messageA ...interface{}) { + gitHubSourceCondSet.Manage(s).MarkFalse(GitHubSourceConditionSecretsProvided, reason, messageFormat, messageA...) +} + +// MarkSink sets the condition that the source has a sink configured. +func (s *GitHubSourceStatus) MarkSink(uri string) { + s.SinkURI = uri + if len(uri) > 0 { + gitHubSourceCondSet.Manage(s).MarkTrue(GitHubSourceConditionSinkProvided) + } else { + gitHubSourceCondSet.Manage(s).MarkUnknown(GitHubSourceConditionSinkProvided, + "SinkEmpty", "Sink has resolved to empty.") + } +} + +// MarkNoSink sets the condition that the source does not have a sink configured. +func (s *GitHubSourceStatus) MarkNoSink(reason, messageFormat string, messageA ...interface{}) { + gitHubSourceCondSet.Manage(s).MarkFalse(GitHubSourceConditionSinkProvided, reason, messageFormat, messageA...) +} + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// GitHubSource is the Schema for the githubsources API +// +k8s:openapi-gen=true +// +kubebuilder:subresource:status +// +kubebuilder:categories=all,knative,eventing,sources +type GitHubSource struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec GitHubSourceSpec `json:"spec,omitempty"` + Status GitHubSourceStatus `json:"status,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// GitHubSourceList contains a list of GitHubSource +type GitHubSourceList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []GitHubSource `json:"items"` +} + +func init() { + SchemeBuilder.Register(&GitHubSource{}, &GitHubSourceList{}) +} diff --git a/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/kuberneteseventsource_types.go b/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/kuberneteseventsource_types.go new file mode 100644 index 00000000000..39c5394198a --- /dev/null +++ b/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/kuberneteseventsource_types.go @@ -0,0 +1,122 @@ +/* +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/duck" + duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +// Check that KubernetesEventSource can be validated and can be defaulted. +var _ runtime.Object = (*KubernetesEventSource)(nil) + +// Check that KubernetesEventSource implements the Conditions duck type. +var _ = duck.VerifyType(&KubernetesEventSource{}, &duckv1alpha1.Conditions{}) + +// KubernetesEventSourceSpec defines the desired state of the source. +type KubernetesEventSourceSpec struct { + // Namespace that we watch kubernetes events in. + Namespace string `json:"namespace"` + + // ServiceAccountName is the name of the ServiceAccount to use to run this + // source. + // +optional + ServiceAccountName string `json:"serviceAccountName,omitempty"` + + // Sink is a reference to an object that will resolve to a domain name to use + // as the sink. + // +optional + Sink *corev1.ObjectReference `json:"sink,omitempty"` +} + +const ( + // KubernetesEventSourceConditionReady has status True when the + // source is ready to send events. + KubernetesEventSourceConditionReady = duckv1alpha1.ConditionReady +) + +var kubernetesEventSourceCondSet = duckv1alpha1.NewLivingConditionSet() + +// KubernetesEventSourceStatus defines the observed state of the source. +type KubernetesEventSourceStatus struct { + // 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"` + + // SinkURI is the current active sink URI that has been configured for the source. + // +optional + SinkURI string `json:"sinkUri,omitempty"` +} + +// GetCondition returns the condition currently associated with the given type, or nil. +func (s *KubernetesEventSourceStatus) GetCondition(t duckv1alpha1.ConditionType) *duckv1alpha1.Condition { + return kubernetesEventSourceCondSet.Manage(s).GetCondition(t) +} + +// IsReady returns true if the resource is ready overall. +func (s *KubernetesEventSourceStatus) IsReady() bool { + return kubernetesEventSourceCondSet.Manage(s).IsHappy() +} + +// InitializeConditions sets relevant unset conditions to Unknown state. +func (s *KubernetesEventSourceStatus) InitializeConditions() { + kubernetesEventSourceCondSet.Manage(s).InitializeConditions() +} + +// MarkReady sets the condition that the ContainerSource owned by +// the source has Ready status True. +func (s *KubernetesEventSourceStatus) MarkReady() { + kubernetesEventSourceCondSet.Manage(s).MarkTrue(KubernetesEventSourceConditionReady) +} + +// MarkUnready sets the condition that the ContainerSource owned by +// the source does not have Ready status True. +func (s *KubernetesEventSourceStatus) MarkUnready(reason, messageFormat string, messageA ...interface{}) { + kubernetesEventSourceCondSet.Manage(s).MarkFalse(KubernetesEventSourceConditionReady, reason, messageFormat, messageA...) +} + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// KubernetesEventSource is the Schema for the kuberneteseventsources API +// +k8s:openapi-gen=true +// +kubebuilder:subresource:status +// +kubebuilder:categories=all,knative,eventing,sources +type KubernetesEventSource struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec KubernetesEventSourceSpec `json:"spec,omitempty"` + Status KubernetesEventSourceStatus `json:"status,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// KubernetesEventSourceList contains a list of KubernetesEventSource +type KubernetesEventSourceList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []KubernetesEventSource `json:"items"` +} + +func init() { + SchemeBuilder.Register(&KubernetesEventSource{}, &KubernetesEventSourceList{}) +} diff --git a/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/register.go b/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/register.go new file mode 100644 index 00000000000..fa5f80118ce --- /dev/null +++ b/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/register.go @@ -0,0 +1,45 @@ +/* +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. +*/ + +// NOTE: Boilerplate only. Ignore this file. + +// Package v1alpha1 contains API Schema definitions for the sources v1alpha1 API group +// +k8s:openapi-gen=true +// +k8s:deepcopy-gen=package,register +// +k8s:conversion-gen=github.com/knative/eventing-sources/pkg/apis/sources +// +k8s:defaulter-gen=TypeMeta +// +groupName=sources.eventing.knative.dev +package v1alpha1 + +import ( + "k8s.io/apimachinery/pkg/runtime/schema" + "sigs.k8s.io/controller-runtime/pkg/runtime/scheme" +) + +var ( + // SchemeGroupVersion is group version used to register these objects + SchemeGroupVersion = schema.GroupVersion{Group: "sources.eventing.knative.dev", Version: "v1alpha1"} + + // SchemeBuilder is used to add go types to the GroupVersionKind scheme + SchemeBuilder = &scheme.Builder{GroupVersion: SchemeGroupVersion} + + AddToScheme = SchemeBuilder.AddToScheme +) + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} diff --git a/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/zz_generated.deepcopy.go b/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/zz_generated.deepcopy.go new file mode 100644 index 00000000000..2dbe589a81f --- /dev/null +++ b/vendor/github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1/zz_generated.deepcopy.go @@ -0,0 +1,562 @@ +// +build !ignore_autogenerated + +/* +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 deepcopy-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + v1 "k8s.io/api/core/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 *AwsSqsSource) DeepCopyInto(out *AwsSqsSource) { + *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 AwsSqsSource. +func (in *AwsSqsSource) DeepCopy() *AwsSqsSource { + if in == nil { + return nil + } + out := new(AwsSqsSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *AwsSqsSource) 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 *AwsSqsSourceList) DeepCopyInto(out *AwsSqsSourceList) { + *out = *in + out.TypeMeta = in.TypeMeta + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]AwsSqsSource, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AwsSqsSourceList. +func (in *AwsSqsSourceList) DeepCopy() *AwsSqsSourceList { + if in == nil { + return nil + } + out := new(AwsSqsSourceList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *AwsSqsSourceList) 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 *AwsSqsSourceSpec) DeepCopyInto(out *AwsSqsSourceSpec) { + *out = *in + in.AwsCredsSecret.DeepCopyInto(&out.AwsCredsSecret) + if in.Sink != nil { + in, out := &in.Sink, &out.Sink + *out = new(v1.ObjectReference) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AwsSqsSourceSpec. +func (in *AwsSqsSourceSpec) DeepCopy() *AwsSqsSourceSpec { + if in == nil { + return nil + } + out := new(AwsSqsSourceSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AwsSqsSourceStatus) DeepCopyInto(out *AwsSqsSourceStatus) { + *out = *in + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AwsSqsSourceStatus. +func (in *AwsSqsSourceStatus) DeepCopy() *AwsSqsSourceStatus { + if in == nil { + return nil + } + out := new(AwsSqsSourceStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ContainerSource) DeepCopyInto(out *ContainerSource) { + *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 ContainerSource. +func (in *ContainerSource) DeepCopy() *ContainerSource { + if in == nil { + return nil + } + out := new(ContainerSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ContainerSource) 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 *ContainerSourceList) DeepCopyInto(out *ContainerSourceList) { + *out = *in + out.TypeMeta = in.TypeMeta + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]ContainerSource, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ContainerSourceList. +func (in *ContainerSourceList) DeepCopy() *ContainerSourceList { + if in == nil { + return nil + } + out := new(ContainerSourceList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ContainerSourceList) 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 *ContainerSourceSpec) DeepCopyInto(out *ContainerSourceSpec) { + *out = *in + if in.Args != nil { + in, out := &in.Args, &out.Args + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Env != nil { + in, out := &in.Env, &out.Env + *out = make([]v1.EnvVar, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Sink != nil { + in, out := &in.Sink, &out.Sink + *out = new(v1.ObjectReference) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ContainerSourceSpec. +func (in *ContainerSourceSpec) DeepCopy() *ContainerSourceSpec { + if in == nil { + return nil + } + out := new(ContainerSourceSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ContainerSourceStatus) DeepCopyInto(out *ContainerSourceStatus) { + *out = *in + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ContainerSourceStatus. +func (in *ContainerSourceStatus) DeepCopy() *ContainerSourceStatus { + if in == nil { + return nil + } + out := new(ContainerSourceStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CronJobSource) DeepCopyInto(out *CronJobSource) { + *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 CronJobSource. +func (in *CronJobSource) DeepCopy() *CronJobSource { + if in == nil { + return nil + } + out := new(CronJobSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *CronJobSource) 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 *CronJobSourceList) DeepCopyInto(out *CronJobSourceList) { + *out = *in + out.TypeMeta = in.TypeMeta + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]CronJobSource, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CronJobSourceList. +func (in *CronJobSourceList) DeepCopy() *CronJobSourceList { + if in == nil { + return nil + } + out := new(CronJobSourceList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *CronJobSourceList) 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 *CronJobSourceSpec) DeepCopyInto(out *CronJobSourceSpec) { + *out = *in + if in.Sink != nil { + in, out := &in.Sink, &out.Sink + *out = new(v1.ObjectReference) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CronJobSourceSpec. +func (in *CronJobSourceSpec) DeepCopy() *CronJobSourceSpec { + if in == nil { + return nil + } + out := new(CronJobSourceSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CronJobSourceStatus) DeepCopyInto(out *CronJobSourceStatus) { + *out = *in + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CronJobSourceStatus. +func (in *CronJobSourceStatus) DeepCopy() *CronJobSourceStatus { + if in == nil { + return nil + } + out := new(CronJobSourceStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GitHubSource) DeepCopyInto(out *GitHubSource) { + *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 GitHubSource. +func (in *GitHubSource) DeepCopy() *GitHubSource { + if in == nil { + return nil + } + out := new(GitHubSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *GitHubSource) 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 *GitHubSourceList) DeepCopyInto(out *GitHubSourceList) { + *out = *in + out.TypeMeta = in.TypeMeta + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]GitHubSource, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GitHubSourceList. +func (in *GitHubSourceList) DeepCopy() *GitHubSourceList { + if in == nil { + return nil + } + out := new(GitHubSourceList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *GitHubSourceList) 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 *GitHubSourceSpec) DeepCopyInto(out *GitHubSourceSpec) { + *out = *in + if in.EventTypes != nil { + in, out := &in.EventTypes, &out.EventTypes + *out = make([]string, len(*in)) + copy(*out, *in) + } + in.AccessToken.DeepCopyInto(&out.AccessToken) + in.SecretToken.DeepCopyInto(&out.SecretToken) + if in.Sink != nil { + in, out := &in.Sink, &out.Sink + *out = new(v1.ObjectReference) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GitHubSourceSpec. +func (in *GitHubSourceSpec) DeepCopy() *GitHubSourceSpec { + if in == nil { + return nil + } + out := new(GitHubSourceSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GitHubSourceStatus) DeepCopyInto(out *GitHubSourceStatus) { + *out = *in + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GitHubSourceStatus. +func (in *GitHubSourceStatus) DeepCopy() *GitHubSourceStatus { + if in == nil { + return nil + } + out := new(GitHubSourceStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KubernetesEventSource) DeepCopyInto(out *KubernetesEventSource) { + *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 KubernetesEventSource. +func (in *KubernetesEventSource) DeepCopy() *KubernetesEventSource { + if in == nil { + return nil + } + out := new(KubernetesEventSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *KubernetesEventSource) 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 *KubernetesEventSourceList) DeepCopyInto(out *KubernetesEventSourceList) { + *out = *in + out.TypeMeta = in.TypeMeta + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]KubernetesEventSource, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubernetesEventSourceList. +func (in *KubernetesEventSourceList) DeepCopy() *KubernetesEventSourceList { + if in == nil { + return nil + } + out := new(KubernetesEventSourceList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *KubernetesEventSourceList) 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 *KubernetesEventSourceSpec) DeepCopyInto(out *KubernetesEventSourceSpec) { + *out = *in + if in.Sink != nil { + in, out := &in.Sink, &out.Sink + *out = new(v1.ObjectReference) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubernetesEventSourceSpec. +func (in *KubernetesEventSourceSpec) DeepCopy() *KubernetesEventSourceSpec { + if in == nil { + return nil + } + out := new(KubernetesEventSourceSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KubernetesEventSourceStatus) DeepCopyInto(out *KubernetesEventSourceStatus) { + *out = *in + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubernetesEventSourceStatus. +func (in *KubernetesEventSourceStatus) DeepCopy() *KubernetesEventSourceStatus { + if in == nil { + return nil + } + out := new(KubernetesEventSourceStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SecretValueFromSource) DeepCopyInto(out *SecretValueFromSource) { + *out = *in + if in.SecretKeyRef != nil { + in, out := &in.SecretKeyRef, &out.SecretKeyRef + *out = new(v1.SecretKeySelector) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretValueFromSource. +func (in *SecretValueFromSource) DeepCopy() *SecretValueFromSource { + if in == nil { + return nil + } + out := new(SecretValueFromSource) + in.DeepCopyInto(out) + return out +} diff --git a/vendor/github.com/knative/eventing-sources/pkg/controller/sdk/finalizers_accessor.go b/vendor/github.com/knative/eventing-sources/pkg/controller/sdk/finalizers_accessor.go new file mode 100644 index 00000000000..f7545ab0d7a --- /dev/null +++ b/vendor/github.com/knative/eventing-sources/pkg/controller/sdk/finalizers_accessor.go @@ -0,0 +1,82 @@ +/* +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 sdk + +import ( + "errors" + "fmt" + "reflect" + + "k8s.io/apimachinery/pkg/util/sets" +) + +// FinalizersAccessor is the interface for a Resource that implements the getter and setting for +// accessing its Finalizer set. +// +k8s:deepcopy-gen=true +type FinalizersAccessor interface { + GetFinalizers() sets.String + SetFinalizers(finalizers sets.String) +} + +// NewReflectedFinalizersAccessor uses reflection to return a FinalizersAccessor to access the field +// called "Finalizers". +func NewReflectedFinalizersAccessor(object interface{}) (FinalizersAccessor, error) { + objectValue := reflect.Indirect(reflect.ValueOf(object)) + + // If object is not a struct, don't even try to use it. + if objectValue.Kind() != reflect.Struct { + return nil, errors.New("object is not a struct") + } + + finalizersField := objectValue.FieldByName("Finalizers") + if finalizersField.IsValid() && finalizersField.CanSet() && finalizersField.Kind() == reflect.Slice { + finalizers := sets.NewString() + for i := 0; i < finalizersField.Len(); i++ { + finalizer := finalizersField.Index(i) + if finalizer.IsValid() && finalizer.Kind() == reflect.String { + finalizers.Insert(finalizer.String()) + } else { + return nil, fmt.Errorf("element in the Finalizer slice was not a string: %v", finalizer.Kind()) + } + } + return &reflectedFinalizersAccessor{ + finalizersField: finalizersField, + finalizersSet: finalizers, + }, nil + } + + return nil, fmt.Errorf("finalizer was not a slice: %v", finalizersField.Kind()) +} + +// reflectedFinalizersAccessor is an internal wrapper object to act as the FinalizersAccessor for +// objects that do not implement FinalizersAccessor directly, but do expose the field using the +// name "Finalizers". +type reflectedFinalizersAccessor struct { + finalizersField reflect.Value + finalizersSet sets.String +} + +// GetFinalizers uses reflection to return the Finalizers set from the held object. +func (r *reflectedFinalizersAccessor) GetFinalizers() sets.String { + return r.finalizersSet +} + +// SetFinalizers uses reflection to set Finalizers on the held object. +func (r *reflectedFinalizersAccessor) SetFinalizers(finalizers sets.String) { + r.finalizersSet = finalizers + r.finalizersField.Set(reflect.ValueOf(finalizers.List())) +} diff --git a/vendor/github.com/knative/eventing-sources/pkg/controller/sdk/provider.go b/vendor/github.com/knative/eventing-sources/pkg/controller/sdk/provider.go new file mode 100644 index 00000000000..664de9daf0e --- /dev/null +++ b/vendor/github.com/knative/eventing-sources/pkg/controller/sdk/provider.go @@ -0,0 +1,74 @@ +/* +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 sdk + +import ( + "context" + + "k8s.io/apimachinery/pkg/runtime" + "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/runtime/inject" + "sigs.k8s.io/controller-runtime/pkg/source" +) + +type KnativeReconciler interface { + Reconcile(ctx context.Context, object runtime.Object) error + inject.Client +} + +type Provider struct { + AgentName string + // Parent is a resource kind to reconcile with empty content. i.e. &v1.Parent{} + Parent runtime.Object + // Owns are dependent resources owned by the parent for which changes to + // those resources cause the Parent to be re-reconciled. This is a list of + // resources of kind with empty content. i.e. [&v1.Child{}] + Owns []runtime.Object + + Reconciler KnativeReconciler +} + +// ProvideController returns a controller for controller-runtime. +func (p *Provider) Add(mgr manager.Manager) error { + // Setup a new controller to Reconcile Subscriptions. + c, err := controller.New(p.AgentName, mgr, controller.Options{ + Reconciler: &Reconciler{ + provider: *p, + recorder: mgr.GetRecorder(p.AgentName), + }, + }) + if err != nil { + return err + } + + // Watch Parent events and enqueue Parent object key. + if err := c.Watch(&source.Kind{Type: p.Parent}, &handler.EnqueueRequestForObject{}); err != nil { + return err + } + + // Watch and enqueue for owning obj key. + for _, t := range p.Owns { + if err := c.Watch(&source.Kind{Type: t}, + &handler.EnqueueRequestForOwner{OwnerType: p.Parent, IsController: true}); err != nil { + return err + } + } + + return nil +} diff --git a/vendor/github.com/knative/eventing-sources/pkg/controller/sdk/reconciler.go b/vendor/github.com/knative/eventing-sources/pkg/controller/sdk/reconciler.go new file mode 100644 index 00000000000..58d39d25122 --- /dev/null +++ b/vendor/github.com/knative/eventing-sources/pkg/controller/sdk/reconciler.go @@ -0,0 +1,186 @@ +/* +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 sdk + +import ( + "context" + + "go.uber.org/zap" + + "github.com/knative/pkg/logging" + "k8s.io/apimachinery/pkg/api/equality" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/record" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + "sigs.k8s.io/controller-runtime/pkg/runtime/inject" +) + +type Reconciler struct { + client client.Client + recorder record.EventRecorder + scheme *runtime.Scheme + + provider Provider +} + +// Verify the struct implements reconcile.Reconciler +var _ reconcile.Reconciler = &Reconciler{} + +// Reconcile compares the actual state with the desired, and attempts to +// converge the two. +func (r *Reconciler) Reconcile(request reconcile.Request) (reconcile.Result, error) { + ctx := context.TODO() + logger := logging.FromContext(ctx) + + logger.Infof("Reconciling %s %v", r.provider.Parent.GetObjectKind(), request) + + original := r.provider.Parent.DeepCopyObject() + + err := r.client.Get(context.TODO(), request.NamespacedName, original) + + if errors.IsNotFound(err) { + logger.Errorf("could not find %s %v\n", r.provider.Parent.GetObjectKind(), request) + return reconcile.Result{}, nil + } + + if err != nil { + logger.Errorf("could not fetch %s %v for %+v\n", r.provider.Parent.GetObjectKind(), err, request) + return reconcile.Result{}, err + } + + // Don't modify the cache's copy + obj := original.DeepCopyObject() + + // Reconcile this copy of the Source and then write back any status + // updates regardless of whether the reconcile error out. + reconcileErr := r.provider.Reconciler.Reconcile(ctx, obj) + if reconcileErr != nil { + logger.Warnf("Failed to reconcile %s: %v", r.provider.Parent.GetObjectKind(), reconcileErr) + } + + if needsUpdate, err := r.needsUpdate(ctx, original, obj); err != nil { + logger.Desugar().Error("Unable to determine if an update is needed", zap.Error(err), zap.Any("original", original), zap.Any("obj", obj)) + return reconcile.Result{}, err + } else if needsUpdate { + if _, err := r.update(ctx, request, obj); err != nil { + logger.Desugar().Error("Failed to update", zap.Error(err), zap.Any("objectKind", r.provider.Parent.GetObjectKind())) + return reconcile.Result{}, err + } + } + + // Requeue if the resource is not ready: + return reconcile.Result{}, reconcileErr +} + +func (r *Reconciler) InjectClient(c client.Client) error { + r.client = c + _, err := inject.ClientInto(c, r.provider.Reconciler) + return err +} + +func (r *Reconciler) InjectConfig(c *rest.Config) error { + _, err := inject.ConfigInto(c, r.provider.Reconciler) + return err +} + +func (r *Reconciler) needsUpdate(ctx context.Context, old, new runtime.Object) (bool, error) { + if old == nil { + return true, nil + } + + // Check Status. + os, err := NewReflectedStatusAccessor(old) + if err != nil { + return false, err + } + ns, err := NewReflectedStatusAccessor(new) + if err != nil { + return false, err + } + oStatus := os.GetStatus() + nStatus := ns.GetStatus() + + if !equality.Semantic.DeepEqual(oStatus, nStatus) { + return true, nil + } + + // Check finalizers. + of, err := NewReflectedFinalizersAccessor(old) + if err != nil { + return false, err + } + nf, err := NewReflectedFinalizersAccessor(new) + if err != nil { + return false, err + } + oFinalizers := of.GetFinalizers() + nFinalizers := nf.GetFinalizers() + + if !equality.Semantic.DeepEqual(oFinalizers, nFinalizers) { + return true, nil + } + + return false, nil +} + +func (r *Reconciler) update(ctx context.Context, request reconcile.Request, object runtime.Object) (runtime.Object, error) { + freshObj := r.provider.Parent.DeepCopyObject() + if err := r.client.Get(ctx, request.NamespacedName, freshObj); err != nil { + return nil, err + } + + // Finalizers + freshFinalizers, err := NewReflectedFinalizersAccessor(freshObj) + if err != nil { + return nil, err + } + orgFinalizers, err := NewReflectedFinalizersAccessor(object) + if err != nil { + return nil, err + } + freshFinalizers.SetFinalizers(orgFinalizers.GetFinalizers()) + + if err := r.client.Update(ctx, freshObj); err != nil { + return nil, err + } + + // Refetch + freshObj = r.provider.Parent.DeepCopyObject() + if err := r.client.Get(ctx, request.NamespacedName, freshObj); err != nil { + return nil, err + } + + // Status + freshStatus, err := NewReflectedStatusAccessor(freshObj) + if err != nil { + return nil, err + } + orgStatus, err := NewReflectedStatusAccessor(object) + if err != nil { + return nil, err + } + freshStatus.SetStatus(orgStatus.GetStatus()) + + if err := r.client.Status().Update(ctx, freshObj); err != nil { + return nil, err + } + + return freshObj, nil +} diff --git a/vendor/github.com/knative/eventing-sources/pkg/controller/sdk/status_accessor.go b/vendor/github.com/knative/eventing-sources/pkg/controller/sdk/status_accessor.go new file mode 100644 index 00000000000..f5aa7c2c18a --- /dev/null +++ b/vendor/github.com/knative/eventing-sources/pkg/controller/sdk/status_accessor.go @@ -0,0 +1,77 @@ +/* +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 sdk + +import ( + "errors" + "fmt" + "reflect" +) + +// StatusAccessor is the interface for a Resource that implements the getter and +// setter for accessing a Condition collection. +// +k8s:deepcopy-gen=true +type StatusAccessor interface { + GetStatus() interface{} + SetStatus(interface{}) +} + +// NewReflectedStatusAccessor uses reflection to return a StatusAccessor +// to access the field called "Status". +func NewReflectedStatusAccessor(object interface{}) (StatusAccessor, error) { + objectValue := reflect.Indirect(reflect.ValueOf(object)) + + // If object is not a struct, don't even try to use it. + if objectValue.Kind() != reflect.Struct { + return nil, errors.New("object is not a struct") + } + + statusField := objectValue.FieldByName("Status") + + if statusField.IsValid() && statusField.CanInterface() && statusField.CanSet() { + if _, ok := statusField.Interface().(interface{}); ok { + return &reflectedStatusAccessor{ + status: statusField, + }, nil + } + } + return nil, fmt.Errorf("status was not an interface: %v", statusField.Kind()) +} + +// reflectedConditionsAccessor is an internal wrapper object to act as the +// ConditionsAccessor for status objects that do not implement ConditionsAccessor +// directly, but do expose the field using the "Conditions" field name. +type reflectedStatusAccessor struct { + status reflect.Value +} + +// GetConditions uses reflection to return Conditions from the held status object. +func (r *reflectedStatusAccessor) GetStatus() interface{} { + if r != nil && r.status.IsValid() && r.status.CanInterface() { + if status, ok := r.status.Interface().(interface{}); ok { + return status + } + } + return nil +} + +// SetConditions uses reflection to set Conditions on the held status object. +func (r *reflectedStatusAccessor) SetStatus(status interface{}) { + if r != nil && r.status.IsValid() && r.status.CanSet() { + r.status.Set(reflect.ValueOf(status)) + } +} diff --git a/vendor/github.com/knative/eventing-sources/pkg/controller/testing/mock_client.go b/vendor/github.com/knative/eventing-sources/pkg/controller/testing/mock_client.go new file mode 100644 index 00000000000..056199bc2d4 --- /dev/null +++ b/vendor/github.com/knative/eventing-sources/pkg/controller/testing/mock_client.go @@ -0,0 +1,153 @@ +/* +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 testing + +import ( + "context" + + "k8s.io/apimachinery/pkg/runtime" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +type MockHandled int + +const ( + // This mock has handled the function call, no further mocks nor the real client should be + // called. + Handled MockHandled = iota + // This mock has not handled the function call, subsequent mocks or the real client should be + // called. + Unhandled +) + +// All of the funcions in client.Client get mocked equivalents. For the function +// client.Client.Foo(), the mocked equivalent will be: +// func(innerClient client.Client[, arguments to Foo()]) (MockHandled[, returns from Foo()]) + +type MockGet func(innerClient client.Client, ctx context.Context, key client.ObjectKey, obj runtime.Object) (MockHandled, error) +type MockList func(innerClient client.Client, ctx context.Context, opts *client.ListOptions, list runtime.Object) (MockHandled, error) +type MockCreate func(innerClient client.Client, ctx context.Context, obj runtime.Object) (MockHandled, error) +type MockDelete func(innerClient client.Client, ctx context.Context, obj runtime.Object) (MockHandled, error) +type MockUpdate func(innerClient client.Client, ctx context.Context, obj runtime.Object) (MockHandled, error) + +var _ client.Client = (*MockClient)(nil) + +// mockClient is a client.Client that allows mock responses to be returned, instead of calling the +// inner client.Client. +type MockClient struct { + innerClient client.Client + mocks Mocks +} + +// The mocks to run on each function type. Each function will run through the mocks in its list +// until one responds with 'Handled'. If there is more than one mock in the list, then the one that +// responds 'Handled' will be removed and not run on subsequent calls to the function. If no mocks +// respond 'Handled', then the real underlying client is called. +type Mocks struct { + MockGets []MockGet + MockLists []MockList + MockCreates []MockCreate + MockDeletes []MockDelete + MockUpdates []MockUpdate +} + +func NewMockClient(innerClient client.Client, mocks Mocks) *MockClient { + return &MockClient{ + innerClient: innerClient, + mocks: mocks, + } +} + +func (m *MockClient) stopMocking() { + m.mocks = Mocks{} +} + +// All of the functions are handled almost identically: +// 1. Run through the mocks in order: +// a. If the mock handled the request, then: +// i. If there is at least one other mock in the list, remove this mock. +// ii. Return the response from the mock. +// 2. No mock handled the request, so call the inner client. + +func (m *MockClient) Get(ctx context.Context, key client.ObjectKey, obj runtime.Object) error { + for i, mockGet := range m.mocks.MockGets { + handled, err := mockGet(m.innerClient, ctx, key, obj) + if handled == Handled { + if len(m.mocks.MockGets) > 1 { + m.mocks.MockGets = append(m.mocks.MockGets[:i], m.mocks.MockGets[i+1:]...) + } + return err + } + } + return m.innerClient.Get(ctx, key, obj) +} + +func (m *MockClient) List(ctx context.Context, opts *client.ListOptions, list runtime.Object) error { + for i, mockList := range m.mocks.MockLists { + handled, err := mockList(m.innerClient, ctx, opts, list) + if handled == Handled { + if len(m.mocks.MockLists) > 1 { + m.mocks.MockLists = append(m.mocks.MockLists[:i], m.mocks.MockLists[i+1:]...) + } + return err + } + } + return m.innerClient.List(ctx, opts, list) +} + +func (m *MockClient) Create(ctx context.Context, obj runtime.Object) error { + for i, mockCreate := range m.mocks.MockCreates { + handled, err := mockCreate(m.innerClient, ctx, obj) + if handled == Handled { + if len(m.mocks.MockCreates) > 1 { + m.mocks.MockCreates = append(m.mocks.MockCreates[:i], m.mocks.MockCreates[i+1:]...) + } + return err + } + } + return m.innerClient.Create(ctx, obj) +} + +func (m *MockClient) Delete(ctx context.Context, obj runtime.Object, opts ...client.DeleteOptionFunc) error { + for i, mockDelete := range m.mocks.MockDeletes { + handled, err := mockDelete(m.innerClient, ctx, obj) + if handled == Handled { + if len(m.mocks.MockDeletes) > 1 { + m.mocks.MockDeletes = append(m.mocks.MockDeletes[:i], m.mocks.MockDeletes[i+1:]...) + } + return err + } + } + return m.innerClient.Delete(ctx, obj, opts...) +} + +func (m *MockClient) Update(ctx context.Context, obj runtime.Object) error { + for i, mockUpdate := range m.mocks.MockUpdates { + handled, err := mockUpdate(m.innerClient, ctx, obj) + if handled == Handled { + if len(m.mocks.MockUpdates) > 1 { + m.mocks.MockUpdates = append(m.mocks.MockUpdates[:i], m.mocks.MockUpdates[i+1:]...) + } + return err + } + } + return m.innerClient.Update(ctx, obj) +} + +func (m *MockClient) Status() client.StatusWriter { + return m.innerClient.Status() +} diff --git a/vendor/github.com/knative/eventing-sources/pkg/controller/testing/table.go b/vendor/github.com/knative/eventing-sources/pkg/controller/testing/table.go new file mode 100644 index 00000000000..bb23d668bf8 --- /dev/null +++ b/vendor/github.com/knative/eventing-sources/pkg/controller/testing/table.go @@ -0,0 +1,275 @@ +/* +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 testing + +import ( + "context" + "fmt" + "strings" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + "github.com/knative/eventing-sources/pkg/controller/sdk" + "github.com/knative/pkg/apis" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/dynamic" + dynamicfake "k8s.io/client-go/dynamic/fake" + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/tools/cache" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + "sigs.k8s.io/controller-runtime/pkg/reconcile" +) + +// TestCase holds a single row of our table test. +type TestCase struct { + // Name is a descriptive name for this test suitable as a first argument to t.Run() + Name string + + // InitialState is the list of objects that already exists when reconciliation + // starts. + InitialState []runtime.Object + + Reconciles runtime.Object + + // ReconcileKey is the key of the object to reconcile in namespace/name form. + ReconcileKey string + + // WantErr is true when we expect the Reconcile function to return an error. + WantErr bool + + // WantErrMsg contains the pattern to match the returned error message. + // Implies WantErr = true. + WantErrMsg string + + // WantResult is the reconcile result we expect to be returned from the + // Reconcile function. + WantResult reconcile.Result + + // WantResultObject is the reconcile result we expect to be returned from the + // Reconcile function. + WantResultObject runtime.Object + + // WantPresent holds the non-exclusive set of objects we expect to exist + // after reconciliation completes. + WantPresent []runtime.Object + + // WantAbsent holds the list of objects expected to not exist + // after reconciliation completes. + WantAbsent []runtime.Object + + // Mocks that tamper with the client's responses. + Mocks Mocks + + // Scheme for the dynamic client + Scheme *runtime.Scheme + + // Fake dynamic objects + Objects []runtime.Object + + // OtherTestData is arbitrary data needed for the test. It is not used directly by the table + // testing framework. Instead it is used in the test method. E.g. setting up the responses for a + // fake GCP PubSub client can go in here, as no other field makes sense for it. + OtherTestData map[string]interface{} + + // IgnoreTimes causes comparisons to ignore fields of type apis.VolatileTime. + IgnoreTimes bool +} + +// Runner returns a testing func that can be passed to t.Run. +func (tc *TestCase) Runner(t *testing.T, r sdk.KnativeReconciler, c *MockClient) func(t *testing.T) { + return func(t *testing.T) { + result, recErr := tc.Reconcile(c, r) + + if err := tc.VerifyErr(recErr); err != nil { + t.Error(err) + } + + // Push back the reconciled changes into the client. + if result != nil { + c.Update(context.TODO(), result) + } + + // Verifying should be done against the innerClient, never against mocks. + c.stopMocking() + + if err := tc.VerifyWantPresent(c); err != nil { + t.Error(err) + } + + if err := tc.VerifyWantAbsent(c); err != nil { + t.Error(err) + } + } +} + +// GetDynamicClient returns the mockDynamicClient to use for this test case. +func (tc *TestCase) GetDynamicClient() dynamic.Interface { + if tc.Scheme == nil { + return dynamicfake.NewSimpleDynamicClient(runtime.NewScheme(), tc.Objects...) + } + return dynamicfake.NewSimpleDynamicClient(tc.Scheme, tc.Objects...) +} + +// GetClient returns the mockClient to use for this test case. +func (tc *TestCase) GetClient() *MockClient { + innerClient := fake.NewFakeClient(tc.InitialState...) + return NewMockClient(innerClient, tc.Mocks) +} + +// Reconcile calls the given reconciler's Reconcile() function with the test +// case's reconcile request. +func (tc *TestCase) Reconcile(c client.Client, r sdk.KnativeReconciler) (runtime.Object, error) { + if tc.ReconcileKey == "" { + return nil, fmt.Errorf("test did not set ReconcileKey") + } + ns, n, err := cache.SplitMetaNamespaceKey(tc.ReconcileKey) + if err != nil { + return nil, err + } + + obj := tc.Reconciles.DeepCopyObject() + err = c.Get(context.TODO(), client.ObjectKey{Namespace: ns, Name: n}, obj) + if err != nil { + // Not found is not an error. + return nil, nil + } + + return obj, r.Reconcile(context.TODO(), obj) +} + +// VerifyErr verifies that the given error returned from Reconcile is the error +// expected by the test case. +func (tc *TestCase) VerifyErr(err error) error { + // A non-empty WantErrMsg implies that an error is wanted. + wantErr := tc.WantErr || tc.WantErrMsg != "" + + if wantErr && err == nil { + return fmt.Errorf("want error, got nil") + } + + if !wantErr && err != nil { + return fmt.Errorf("want no error, got %v", err) + } + + if err != nil { + if diff := cmp.Diff(tc.WantErrMsg, err.Error()); diff != "" { + return fmt.Errorf("incorrect error (-want, +got): %v", diff) + } + } + return nil +} + +// VerifyResult verifies that the given result returned from Reconcile is the +// result expected by the test case. +func (tc *TestCase) VerifyResult(result reconcile.Result) error { + if diff := cmp.Diff(tc.WantResult, result); diff != "" { + return fmt.Errorf("unexpected reconcile Result (-want +got) %v", diff) + } + return nil +} + +// VerifyResult verifies that the given result returned from Reconcile is the +// result expected by the test case. +func (tc *TestCase) VerifyResultSDK(result runtime.Object) error { + if diff := cmp.Diff(tc.WantResultObject, result); diff != "" { + return fmt.Errorf("unexpected reconcile Result Object (-want +got) %v", diff) + } + return nil +} + +type stateErrors struct { + errors []error +} + +func (se stateErrors) Error() string { + msgs := make([]string, 0) + for _, err := range se.errors { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "\n") +} + +// VerifyWantPresent verifies that the client contains all the objects expected +// to be present after reconciliation. +func (tc *TestCase) VerifyWantPresent(c client.Client) error { + var errs stateErrors + for _, wp := range tc.WantPresent { + o, err := scheme.Scheme.New(wp.GetObjectKind().GroupVersionKind()) + if err != nil { + errs.errors = append(errs.errors, fmt.Errorf("error creating a copy of %T: %v", wp, err)) + } + acc, err := meta.Accessor(wp) + if err != nil { + errs.errors = append(errs.errors, fmt.Errorf("error getting accessor for %#v %v", wp, err)) + } + err = c.Get(context.TODO(), client.ObjectKey{Namespace: acc.GetNamespace(), Name: acc.GetName()}, o) + if err != nil { + if apierrors.IsNotFound(err) { + errs.errors = append(errs.errors, fmt.Errorf("want present %T %s/%s, got absent", wp, acc.GetNamespace(), acc.GetName())) + } else { + errs.errors = append(errs.errors, fmt.Errorf("error getting %T %s/%s: %v", wp, acc.GetNamespace(), acc.GetName(), err)) + } + } + + diffOpts := cmp.Options{ + // Ignore TypeMeta, since the objects created by the controller won't have + // it + cmpopts.IgnoreTypes(metav1.TypeMeta{}), + } + + if tc.IgnoreTimes { + // Ignore VolatileTime fields, since they rarely compare correctly. + diffOpts = append(diffOpts, cmpopts.IgnoreTypes(apis.VolatileTime{})) + } + + if diff := cmp.Diff(wp, o, diffOpts...); diff != "" { + errs.errors = append(errs.errors, fmt.Errorf("Unexpected present %T %s/%s (-want +got):\n%v", wp, acc.GetNamespace(), acc.GetName(), diff)) + } + } + if len(errs.errors) > 0 { + return errs + } + return nil +} + +// VerifyWantAbsent verifies that the client does not contain any of the objects +// expected to be absent after reconciliation. +func (tc *TestCase) VerifyWantAbsent(c client.Client) error { + var errs stateErrors + for _, wa := range tc.WantAbsent { + acc, err := meta.Accessor(wa) + if err != nil { + errs.errors = append(errs.errors, fmt.Errorf("error getting accessor for %#v %v", wa, err)) + } + err = c.Get(context.TODO(), client.ObjectKey{Namespace: acc.GetNamespace(), Name: acc.GetName()}, wa) + if err == nil { + errs.errors = append(errs.errors, fmt.Errorf("want absent, got present %T %s/%s", wa, acc.GetNamespace(), acc.GetName())) + } + if !apierrors.IsNotFound(err) { + errs.errors = append(errs.errors, fmt.Errorf("error getting %T %s/%s: %v", wa, acc.GetNamespace(), acc.GetName(), err)) + } + } + if len(errs.errors) > 0 { + return errs + } + return nil +} diff --git a/vendor/github.com/knative/eventing-sources/pkg/reconciler/containersource/resources/arguments.go b/vendor/github.com/knative/eventing-sources/pkg/reconciler/containersource/resources/arguments.go new file mode 100644 index 00000000000..9eb2884f4f7 --- /dev/null +++ b/vendor/github.com/knative/eventing-sources/pkg/reconciler/containersource/resources/arguments.go @@ -0,0 +1,34 @@ +/* +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 ( + corev1 "k8s.io/api/core/v1" +) + +type ContainerArguments struct { + Name string + Namespace string + Image string + Args []string + Env []corev1.EnvVar + ServiceAccountName string + SinkInArgs bool + Sink string + Annotations map[string]string + Labels map[string]string +} diff --git a/vendor/github.com/knative/eventing-sources/pkg/reconciler/containersource/resources/deployment.go b/vendor/github.com/knative/eventing-sources/pkg/reconciler/containersource/resources/deployment.go new file mode 100644 index 00000000000..2e253dc3531 --- /dev/null +++ b/vendor/github.com/knative/eventing-sources/pkg/reconciler/containersource/resources/deployment.go @@ -0,0 +1,115 @@ +/* +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" + "strings" + + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +const sourceLabelKey = "eventing.knative.dev/source" + +func MakeDeployment(org *appsv1.Deployment, args *ContainerArguments) *appsv1.Deployment { + + containerArgs := []string(nil) + if args != nil { + containerArgs = args.Args + } + // if sink is already in the provided args.Args, don't attempt to add + if !args.SinkInArgs { + remote := fmt.Sprintf("--sink=%s", args.Sink) + containerArgs = append(containerArgs, remote) + } + + env := append(args.Env, corev1.EnvVar{Name: "SINK", Value: sinkArg(args)}) + + deploy := &appsv1.Deployment{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "apps/v1", + Kind: "Deployment", + }, + ObjectMeta: metav1.ObjectMeta{ + GenerateName: args.Name + "-", + Namespace: args.Namespace, + }, + Spec: appsv1.DeploymentSpec{ + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + sourceLabelKey: args.Name, + }, + }, + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + "sidecar.istio.io/inject": "true", + }, + Labels: map[string]string{ + sourceLabelKey: args.Name, + }, + }, + Spec: corev1.PodSpec{ + ServiceAccountName: args.ServiceAccountName, + Containers: []corev1.Container{ + { + Name: "source", + Image: args.Image, + Args: containerArgs, + Env: env, + ImagePullPolicy: corev1.PullIfNotPresent, + }, + }, + }, + }, + }, + } + + // Then wire through any annotations from the source. Not a bug by allowing + // the container to override Istio injection. + if args.Annotations != nil { + for k, v := range args.Annotations { + deploy.Spec.Template.ObjectMeta.Annotations[k] = v + } + } + + // Then wire through any labels from the source. Do not allow to override + // our source name. This seems like it would be way errorprone by allowing + // the matchlabels then to not match, or we'd have to force them to match, etc. + // just don't allow it. + if args.Labels != nil { + for k, v := range args.Labels { + if k != sourceLabelKey { + deploy.Spec.Template.ObjectMeta.Labels[k] = v + } + } + } + return deploy +} + +func sinkArg(args *ContainerArguments) string { + if args.SinkInArgs { + for _, a := range args.Args { + if strings.HasPrefix(a, "--sink=") { + return strings.Replace(a, "--sink=", "", -1) + } + } + } + return args.Sink +} diff --git a/vendor/github.com/knative/eventing-sources/test/test_images/k8sevents/kodata/LICENSE b/vendor/github.com/knative/eventing-sources/test/test_images/k8sevents/kodata/LICENSE new file mode 120000 index 00000000000..14776154326 --- /dev/null +++ b/vendor/github.com/knative/eventing-sources/test/test_images/k8sevents/kodata/LICENSE @@ -0,0 +1 @@ +../../../../LICENSE \ No newline at end of file diff --git a/vendor/github.com/knative/eventing-sources/test/test_images/k8sevents/kodata/VENDOR-LICENSE b/vendor/github.com/knative/eventing-sources/test/test_images/k8sevents/kodata/VENDOR-LICENSE new file mode 120000 index 00000000000..7322c09d957 --- /dev/null +++ b/vendor/github.com/knative/eventing-sources/test/test_images/k8sevents/kodata/VENDOR-LICENSE @@ -0,0 +1 @@ +../../../../third_party/VENDOR-LICENSE \ No newline at end of file diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/runtime/scheme/scheme.go b/vendor/sigs.k8s.io/controller-runtime/pkg/runtime/scheme/scheme.go new file mode 100644 index 00000000000..79868214e34 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/runtime/scheme/scheme.go @@ -0,0 +1,56 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT 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 scheme + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +// Builder builds a new Scheme for mapping go types to Kubernetes GroupVersionKinds. +type Builder struct { + GroupVersion schema.GroupVersion + runtime.SchemeBuilder +} + +// Register adds one or objects to the SchemeBuilder so they can be added to a Scheme. Register mutates bld. +func (bld *Builder) Register(object ...runtime.Object) *Builder { + bld.SchemeBuilder.Register(func(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(bld.GroupVersion, object...) + metav1.AddToGroupVersion(scheme, bld.GroupVersion) + return nil + }) + return bld +} + +// RegisterAll registers all types from the Builder argument. RegisterAll mutates bld. +func (bld *Builder) RegisterAll(b *Builder) *Builder { + bld.SchemeBuilder = append(bld.SchemeBuilder, b.SchemeBuilder...) + return bld +} + +// AddToScheme adds all registered types to s. +func (bld *Builder) AddToScheme(s *runtime.Scheme) error { + return bld.SchemeBuilder.AddToScheme(s) +} + +// Build returns a new Scheme containing the registered types. +func (bld *Builder) Build() (*runtime.Scheme, error) { + s := runtime.NewScheme() + return s, bld.AddToScheme(s) +} From 76679e92c180a4abf03f66a123aea05fbc74a657 Mon Sep 17 00:00:00 2001 From: Scott Nichols Date: Thu, 25 Apr 2019 08:13:16 -0700 Subject: [PATCH 21/25] stagging for test writing.: --- .../containersource/containersource.go | 10 +- .../containersource/containersource_test.go | 847 ++++++------------ .../containersource/resources/deployment.go | 10 +- .../resources/deployment_test.go | 6 +- pkg/reconciler/testing/listers.go | 4 + 5 files changed, 289 insertions(+), 588 deletions(-) diff --git a/pkg/reconciler/containersource/containersource.go b/pkg/reconciler/containersource/containersource.go index 7cc8058e77f..6d91e8a7e77 100644 --- a/pkg/reconciler/containersource/containersource.go +++ b/pkg/reconciler/containersource/containersource.go @@ -159,7 +159,7 @@ func (r *Reconciler) reconcile(ctx context.Context, source *v1alpha1.ContainerSo } } - args := &resources.ContainerArguments{ + args := resources.ContainerArguments{ Source: source, Name: source.Name, Namespace: source.Namespace, @@ -171,7 +171,7 @@ func (r *Reconciler) reconcile(ctx context.Context, source *v1alpha1.ContainerSo Labels: labels, } - err := r.setSinkURIArg(ctx, source, args) + err := r.setSinkURIArg(ctx, source, &args) if err != nil { r.Recorder.Eventf(source, corev1.EventTypeWarning, "SetSinkURIFailed", "Failed to set Sink URI: %v", err) return err @@ -197,7 +197,7 @@ func (r *Reconciler) reconcile(ctx context.Context, source *v1alpha1.ContainerSo } // Update Deployment spec if it's changed - expected := resources.MakeDeployment(nil, args) + expected := resources.MakeDeployment(args) // Since the Deployment spec has fields defaulted by the webhook, it won't // be equal to expected. Use DeepDerivative to compare only the fields that // are set in expected. @@ -273,8 +273,8 @@ func (r *Reconciler) getDeployment(ctx context.Context, source *v1alpha1.Contain return nil, errors.NewNotFound(schema.GroupResource{}, "") } -func (r *Reconciler) createDeployment(ctx context.Context, source *v1alpha1.ContainerSource, org *appsv1.Deployment, args *resources.ContainerArguments) (*appsv1.Deployment, error) { - deployment := resources.MakeDeployment(org, args) +func (r *Reconciler) createDeployment(ctx context.Context, source *v1alpha1.ContainerSource, org *appsv1.Deployment, args resources.ContainerArguments) (*appsv1.Deployment, error) { + deployment := resources.MakeDeployment(args) return r.KubeClientSet.AppsV1().Deployments(source.Namespace).Create(deployment) } diff --git a/pkg/reconciler/containersource/containersource_test.go b/pkg/reconciler/containersource/containersource_test.go index 64d0f3a28a2..e2052340883 100644 --- a/pkg/reconciler/containersource/containersource_test.go +++ b/pkg/reconciler/containersource/containersource_test.go @@ -17,36 +17,55 @@ limitations under the License. package containersource import ( - "context" - "encoding/json" - "errors" - "fmt" + "github.com/knative/eventing/pkg/utils" "testing" - "github.com/google/go-cmp/cmp" - sourcesv1alpha1 "github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1" - controllertesting "github.com/knative/eventing-sources/pkg/controller/testing" - "github.com/knative/eventing-sources/pkg/reconciler/containersource/resources" + //clientgotesting "k8s.io/client-go/testing" + + fakeclientset "github.com/knative/eventing/pkg/client/clientset/versioned/fake" + informers "github.com/knative/eventing/pkg/client/informers/externalversions" + "github.com/knative/eventing/pkg/reconciler" duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" - appsv1 "k8s.io/api/apps/v1" + "github.com/knative/pkg/controller" + logtesting "github.com/knative/pkg/logging/testing" 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" + //metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + //"k8s.io/apimachinery/pkg/runtime" + kubeinformers "k8s.io/client-go/informers" + fakekubeclientset "k8s.io/client-go/kubernetes/fake" "k8s.io/client-go/kubernetes/scheme" - "k8s.io/client-go/tools/record" - "sigs.k8s.io/controller-runtime/pkg/client" + + . "github.com/knative/eventing/pkg/reconciler/testing" + . "github.com/knative/pkg/reconciler/testing" + + //sourcesv1alpha1 "github.com/knative/eventing/pkg/apis/sources/v1alpha1" + v1 "k8s.io/api/apps/v1" +) + +const ( + image = "github.com/knative/test/image" + sourceName = "test-container-source" + sourceUID = "1234-5678-90" + testNS = "testnamespace" + testData = "data" + sinkName = "testsink" ) var ( trueVal = true targetURI = "http://addressable.sink.svc.cluster.local/" + + sinkRef = corev1.ObjectReference{ + Name: sinkName, + Kind: "Channel", + APIVersion: "eventing.knative.dev/v1alpha1", + } + sinkDNS = "sink.mynamespace.svc." + utils.GetClusterDomainName() + sinkURI = "http://" + sinkDNS + "/" ) const ( - image = "github.com/knative/test/image" containerSourceName = "testcontainersource" - testNS = "testnamespace" containerSourceUID = "2a2208d1-ce67-11e8-b3a3-42010a8a00af" deployGeneratedName = "" //sad trombone @@ -67,576 +86,256 @@ const ( func init() { // Add types to scheme - sourcesv1alpha1.SchemeBuilder.AddToScheme(scheme.Scheme) - duckv1alpha1.AddToScheme(scheme.Scheme) + _ = v1.AddToScheme(scheme.Scheme) + _ = corev1.AddToScheme(scheme.Scheme) + _ = duckv1alpha1.AddToScheme(scheme.Scheme) } -var testCases = []controllertesting.TestCase{ - { - Name: "non existent key", - Reconciles: &sourcesv1alpha1.ContainerSource{}, - ReconcileKey: "non-existent-test-ns/non-existent-test-key", - WantErr: false, - }, { - Name: "valid containersource, but sink does not exist", - Reconciles: &sourcesv1alpha1.ContainerSource{}, - InitialState: []runtime.Object{ - getContainerSource(), - }, - ReconcileKey: fmt.Sprintf("%s/%s", testNS, containerSourceName), - WantErrMsg: `sinks.duck.knative.dev "testsink" not found`, - }, { - Name: "valid containersource, but sink is not addressable", - Reconciles: &sourcesv1alpha1.ContainerSource{}, - InitialState: []runtime.Object{ - getContainerSourceUnaddressable(), - getAddressableNoStatus(), - }, - ReconcileKey: fmt.Sprintf("%s/%s", testNS, containerSourceName), - Scheme: scheme.Scheme, - WantErrMsg: `sink "testnamespace/testunaddressable" (duck.knative.dev/v1alpha1, Kind=KResource) does not contain address`, - }, { - Name: "valid containersource, sink is addressable", - Reconciles: &sourcesv1alpha1.ContainerSource{}, - InitialState: []runtime.Object{ - getContainerSource(), - getAddressable(), - }, - ReconcileKey: fmt.Sprintf("%s/%s", testNS, containerSourceName), - Scheme: scheme.Scheme, - WantPresent: []runtime.Object{ - func() runtime.Object { - s := getContainerSource() - s.Status.InitializeConditions() - s.Status.MarkDeploying("DeploymentCreated", "Created deployment %q", deployGeneratedName) - s.Status.MarkSink(targetURI) - return s - }(), - }, - IgnoreTimes: true, - }, { - Name: "valid containersource, sink is addressable, fields filled in", - Reconciles: &sourcesv1alpha1.ContainerSource{}, - InitialState: []runtime.Object{ - getContainerSourceFilledIn(), - getAddressable(), - }, - ReconcileKey: fmt.Sprintf("%s/%s", testNS, containerSourceName), - Scheme: scheme.Scheme, - WantPresent: []runtime.Object{ - getDeployment(getContainerSourceFilledIn()), - }, - IgnoreTimes: true, - }, { - Name: "valid containersource, sink is Addressable but sink is nil", - Reconciles: &sourcesv1alpha1.ContainerSource{}, - InitialState: []runtime.Object{ - getContainerSource(), - getAddressableNilAddress(), - }, - ReconcileKey: fmt.Sprintf("%s/%s", testNS, containerSourceName), - Scheme: scheme.Scheme, - WantPresent: []runtime.Object{ - func() runtime.Object { - s := getContainerSource() - s.Status.InitializeConditions() - s.Status.MarkNoSink("NotFound", `Couldn't get Sink URI from "/testsink": sink "testnamespace/testsink" (duck.knative.dev/v1alpha1, Kind=Sink) does not contain address"`) - return s - }(), - }, - IgnoreTimes: true, - WantErrMsg: `sink "testnamespace/testsink" (duck.knative.dev/v1alpha1, Kind=Sink) does not contain address`, - }, { - Name: "invalid containersource, sink is nil", - Reconciles: &sourcesv1alpha1.ContainerSource{}, - InitialState: []runtime.Object{ - func() runtime.Object { - s := getContainerSource() - s.Spec.Sink = nil - return s - }(), - }, - ReconcileKey: fmt.Sprintf("%s/%s", testNS, containerSourceName), - Scheme: scheme.Scheme, - WantPresent: []runtime.Object{ - func() runtime.Object { - s := getContainerSource() - s.Spec.Sink = nil - s.Status.InitializeConditions() - s.Status.MarkNoSink("Missing", "Sink missing from spec") - return s - }(), - }, - IgnoreTimes: true, - WantErrMsg: `Sink missing from spec`, - }, { - Name: "valid containersource, sink is provided", - Reconciles: &sourcesv1alpha1.ContainerSource{}, - InitialState: []runtime.Object{ - func() runtime.Object { - s := getContainerSource() - s.Spec.Sink = nil - s.Spec.Args = append(s.Spec.Args, fmt.Sprintf("--sink=%s", targetURI)) - return s - }(), - }, - ReconcileKey: fmt.Sprintf("%s/%s", testNS, containerSourceName), - Scheme: scheme.Scheme, - WantPresent: []runtime.Object{ - func() runtime.Object { - s := getContainerSource() - s.Spec.Sink = nil - s.Spec.Args = append(s.Spec.Args, fmt.Sprintf("--sink=%s", targetURI)) - s.Status.InitializeConditions() - s.Status.MarkDeploying("DeploymentCreated", "Created deployment %q", deployGeneratedName) - s.Status.MarkSink(targetURI) - return s - }(), - }, - IgnoreTimes: true, - }, { - Name: "valid containersource, labels and annotations given", - Reconciles: &sourcesv1alpha1.ContainerSource{}, - InitialState: []runtime.Object{ - func() runtime.Object { - s := getContainerSource() - s.Spec.Sink = nil - s.Spec.Args = append(s.Spec.Args, fmt.Sprintf("--sink=%s", targetURI)) - s.ObjectMeta.Annotations = map[string]string{"annotation": "solid"} - s.ObjectMeta.Labels = map[string]string{"label": "soliderer"} - return s - }(), - }, - ReconcileKey: fmt.Sprintf("%s/%s", testNS, containerSourceName), - Scheme: scheme.Scheme, - WantPresent: []runtime.Object{ - func() runtime.Object { - s := getContainerSource() - s.Spec.Sink = nil - s.Spec.Args = append(s.Spec.Args, fmt.Sprintf("--sink=%s", targetURI)) - s.Status.InitializeConditions() - s.Status.MarkDeploying("DeploymentCreated", "Created deployment %q", deployGeneratedName) - s.Status.MarkSink(targetURI) - s.ObjectMeta.Annotations = map[string]string{"annotation": "solid"} - s.ObjectMeta.Labels = map[string]string{"label": "soliderer"} - return s - }(), - }, - IgnoreTimes: true, - }, { - Name: "valid containersource, sink, and deployment", - Reconciles: &sourcesv1alpha1.ContainerSource{}, - InitialState: []runtime.Object{ - func() runtime.Object { - s := getContainerSource() - s.UID = containerSourceUID - return s - }(), - func() runtime.Object { - // TODO(n3wscott): this is very strange, I was not able to get - // the fake client to return the resources.MakeDeployment version - // back in the list call. I might have missed setting some special - // metadata? Converting an unstructured and setting the fields - // I care about did work. - u := &unstructured.Unstructured{ - Object: map[string]interface{}{ - "apiVersion": "apps/v1", - "kind": "Deployment", - "metadata": map[string]interface{}{ - "namespace": testNS, - "name": containerSourceName + "-abc", - }, - }, - } - u.SetOwnerReferences(getOwnerReferences()) - - d := &appsv1.Deployment{} - d.Status.ReadyReplicas = 1 - j, _ := u.MarshalJSON() - json.Unmarshal(j, d) - - d1 := resources.MakeDeployment(nil, &resources.ContainerArguments{ - Name: containerSourceName, - Sink: "http://" + addressableDNS + "/", - Image: image, - }) - d.Spec = d1.Spec - return d - }(), - getAddressable(), - }, - ReconcileKey: fmt.Sprintf("%s/%s", testNS, containerSourceName), - Scheme: scheme.Scheme, - WantPresent: []runtime.Object{ - func() runtime.Object { - s := getContainerSource() - s.UID = containerSourceUID - s.Status.InitializeConditions() - s.Status.MarkDeployed() - s.Status.MarkSink(targetURI) - return s - }(), - }, - IgnoreTimes: true, - }, { - Name: "valid containersource, sink, but deployment needs update", - Reconciles: &sourcesv1alpha1.ContainerSource{}, - InitialState: []runtime.Object{ - func() runtime.Object { - s := getContainerSource() - s.UID = containerSourceUID - return s - }(), - func() runtime.Object { - // TODO(n3wscott): this is very strange, I was not able to get - // the fake client to return the resources.MakeDeployment version - // back in the list call. I might have missed setting some special - // metadata? Converting an unstructured and setting the fields - // I care about did work. - u := &unstructured.Unstructured{ - Object: map[string]interface{}{ - "apiVersion": "apps/v1", - "kind": "Deployment", - "metadata": map[string]interface{}{ - "namespace": testNS, - "name": containerSourceName + "-abc", - }, - }, - } - u.SetOwnerReferences(getOwnerReferences()) +func TestNew(t *testing.T) { + defer logtesting.ClearAll() + kubeClient := fakekubeclientset.NewSimpleClientset() + eventingClient := fakeclientset.NewSimpleClientset() + eventingInformer := informers.NewSharedInformerFactory(eventingClient, 0) + kubeInformer := kubeinformers.NewSharedInformerFactory(kubeClient, 0) - d := &appsv1.Deployment{} - d.Status.ReadyReplicas = 1 - j, _ := u.MarshalJSON() - json.Unmarshal(j, d) + containerSourceInformer := eventingInformer.Sources().V1alpha1().ContainerSources() + deploymentInformer := kubeInformer.Apps().V1().Deployments() - d1 := resources.MakeDeployment(nil, &resources.ContainerArguments{ - Name: containerSourceName, - Sink: "http://old-" + addressableDNS + "/", - Image: image, - }) - d.Spec = d1.Spec - return d - }(), - getAddressable(), - }, - ReconcileKey: fmt.Sprintf("%s/%s", testNS, containerSourceName), - Scheme: scheme.Scheme, - WantPresent: []runtime.Object{ - func() runtime.Object { - s := getContainerSource() - s.UID = containerSourceUID - s.Status.InitializeConditions() - s.Status.MarkDeploying("DeploymentUpdated", "Updated deployment %q", containerSourceName+"-abc") - s.Status.MarkSink(targetURI) - return s - }(), - }, - IgnoreTimes: true, - }, { - Name: "Error for create deployment", - Reconciles: &sourcesv1alpha1.ContainerSource{}, - InitialState: []runtime.Object{ - func() runtime.Object { - s := getContainerSource() - s.UID = containerSourceUID - return s - }(), - getAddressable(), - }, - ReconcileKey: fmt.Sprintf("%s/%s", testNS, containerSourceName), - Scheme: scheme.Scheme, - Mocks: controllertesting.Mocks{ - MockCreates: []controllertesting.MockCreate{ - func(_ client.Client, _ context.Context, _ runtime.Object) (controllertesting.MockHandled, error) { - return controllertesting.Handled, errors.New("force an error into client create") - }, - }, - }, - IgnoreTimes: true, - WantErrMsg: `force an error into client create`, - }, { - Name: "Error for get source, other than not found", - Reconciles: &sourcesv1alpha1.ContainerSource{}, - InitialState: []runtime.Object{ - func() runtime.Object { - s := getContainerSource() - s.UID = containerSourceUID - return s - }(), - getAddressable(), - }, - ReconcileKey: fmt.Sprintf("%s/%s", testNS, containerSourceName), - Scheme: scheme.Scheme, - Mocks: controllertesting.Mocks{ - MockLists: []controllertesting.MockList{ - func(_ client.Client, _ context.Context, _ *client.ListOptions, _ runtime.Object) (controllertesting.MockHandled, error) { - return controllertesting.Handled, errors.New("force an error into client list") - }, - }, - }, - IgnoreTimes: true, - WantErrMsg: `force an error into client list`, + c := NewController(reconciler.Options{ + KubeClientSet: kubeClient, + EventingClientSet: eventingClient, + Logger: logtesting.TestLogger(t), }, - /* TODO: support k8s service { - Name: "valid containersource, sink is a k8s service", - Reconciles: &sourcesv1alpha1.ContainerSource{}, - InitialState: []runtime.Object{ - getContainerSourceSinkService(), - }, - ReconcileKey: fmt.Sprintf("%s/%s", testNS, containerSourceName), - Scheme: scheme.Scheme, - Objects: []runtime.Object{ - // addressable - &unstructured.Unstructured{ - Object: map[string]interface{}{ - "apiVersion": sinkServiceAPIVersion, - "kind": sinkServiceKind, - "metadata": map[string]interface{}{ - "namespace": testNS, - "name": sinkServiceName, - }, - }}, - }, - },*/ -} - -func TestAllCases(t *testing.T) { - recorder := record.NewBroadcaster().NewRecorder(scheme.Scheme, corev1.EventSource{Component: controllerAgentName}) - - for _, tc := range testCases { - c := tc.GetClient() - - r := &reconciler{ - scheme: tc.Scheme, - recorder: recorder, - } - r.InjectClient(c) - t.Run(tc.Name, tc.Runner(t, r, c)) - } -} - -func getContainerSource() *sourcesv1alpha1.ContainerSource { - obj := &sourcesv1alpha1.ContainerSource{ - TypeMeta: containerSourceType(), - ObjectMeta: om(testNS, containerSourceName), - Spec: sourcesv1alpha1.ContainerSourceSpec{ - Image: image, - Args: []string(nil), - Sink: &corev1.ObjectReference{ - Name: addressableName, - Kind: addressableKind, - APIVersion: addressableAPIVersion, - }, - }, - } - // selflink is not filled in when we create the object, so clear it - obj.ObjectMeta.SelfLink = "" - return obj -} - -func getContainerSourceFilledIn() *sourcesv1alpha1.ContainerSource { - obj := getContainerSource() - obj.ObjectMeta.UID = containerSourceUID - obj.Spec.Args = []string{"--foo", "bar"} - obj.Spec.Env = []corev1.EnvVar{{Name: "FOO", Value: "bar"}} - obj.Spec.ServiceAccountName = "foo" - return obj -} - -func getContainerSourceSinkService() *sourcesv1alpha1.ContainerSource { - obj := &sourcesv1alpha1.ContainerSource{ - TypeMeta: containerSourceType(), - ObjectMeta: om(testNS, containerSourceName), - Spec: sourcesv1alpha1.ContainerSourceSpec{ - Image: image, - Args: []string(nil), - Sink: &corev1.ObjectReference{ - Name: sinkServiceName, - Kind: sinkServiceKind, - APIVersion: sinkServiceAPIVersion, - }, - }, - } - // selflink is not filled in when we create the object, so clear it - obj.ObjectMeta.SelfLink = "" - return obj -} - -func getContainerSourceUnaddressable() *sourcesv1alpha1.ContainerSource { - obj := &sourcesv1alpha1.ContainerSource{ - TypeMeta: containerSourceType(), - ObjectMeta: om(testNS, containerSourceName), - Spec: sourcesv1alpha1.ContainerSourceSpec{ - Image: image, - Args: []string{}, - Sink: &corev1.ObjectReference{ - Name: unaddressableName, - Kind: unaddressableKind, - APIVersion: unaddressableAPIVersion, - }, - }, - } - // selflink is not filled in when we create the object, so clear it - obj.ObjectMeta.SelfLink = "" - return obj -} - -func getAddressable() *unstructured.Unstructured { - return &unstructured.Unstructured{ - Object: map[string]interface{}{ - "apiVersion": addressableAPIVersion, - "kind": addressableKind, - "metadata": map[string]interface{}{ - "namespace": testNS, - "name": addressableName, - }, - "status": map[string]interface{}{ - "address": map[string]interface{}{ - "hostname": addressableDNS, - }, - }, - }, - } -} + containerSourceInformer, + deploymentInformer, + ) -func getAddressableNoStatus() *unstructured.Unstructured { - return &unstructured.Unstructured{ - Object: map[string]interface{}{ - "apiVersion": unaddressableAPIVersion, - "kind": unaddressableKind, - "metadata": map[string]interface{}{ - "namespace": testNS, - "name": unaddressableName, - }, - }, + if c == nil { + t.Fatal("Expected NewController to return a non-nil value") } } -func getAddressableNilAddress() *unstructured.Unstructured { - return &unstructured.Unstructured{ - Object: map[string]interface{}{ - "apiVersion": addressableAPIVersion, - "kind": addressableKind, - "metadata": map[string]interface{}{ - "namespace": testNS, - "name": addressableName, - }, - "status": map[string]interface{}{ - "address": map[string]interface{}(nil), - }, - }, - } -} - -func getDeployment(source *sourcesv1alpha1.ContainerSource) *appsv1.Deployment { - addressableURI := fmt.Sprintf("http://%s/", addressableDNS) - args := append(source.Spec.Args, fmt.Sprintf("--sink=%s", addressableURI)) - env := append(source.Spec.Env, corev1.EnvVar{Name: "SINK", Value: addressableURI}) - return &appsv1.Deployment{ - TypeMeta: deploymentType(), - ObjectMeta: metav1.ObjectMeta{ - GenerateName: fmt.Sprintf("%s-", source.Name), - Namespace: source.Namespace, - OwnerReferences: getOwnerReferences(), - }, - Spec: appsv1.DeploymentSpec{ - Selector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - "eventing.knative.dev/source": source.Name, - }, - }, - Template: corev1.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Annotations: map[string]string{ - "sidecar.istio.io/inject": "true", - }, - Labels: map[string]string{ - "eventing.knative.dev/source": source.Name, - }, - }, - Spec: corev1.PodSpec{ - Containers: []corev1.Container{{ - Name: "source", - Image: source.Spec.Image, - Args: args, - Env: env, - ImagePullPolicy: corev1.PullIfNotPresent, - }}, - ServiceAccountName: source.Spec.ServiceAccountName, - }, - }, +func TestAllCases(t *testing.T) { + table := TableTest{ + { + 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", }, } -} - -func containerSourceType() metav1.TypeMeta { - return metav1.TypeMeta{ - APIVersion: sourcesv1alpha1.SchemeGroupVersion.String(), - Kind: "ContainerSource", - } -} - -func deploymentType() metav1.TypeMeta { - return metav1.TypeMeta{ - APIVersion: appsv1.SchemeGroupVersion.String(), - Kind: "Deployment", - } -} - -func om(namespace, name string) metav1.ObjectMeta { - return metav1.ObjectMeta{ - Namespace: namespace, - Name: name, - SelfLink: fmt.Sprintf("/apis/eventing/sources/v1alpha1/namespaces/%s/object/%s", namespace, name), - } -} -func getOwnerReferences() []metav1.OwnerReference { - return []metav1.OwnerReference{{ - APIVersion: sourcesv1alpha1.SchemeGroupVersion.String(), - Kind: "ContainerSource", - Name: containerSourceName, - Controller: &trueVal, - BlockOwnerDeletion: &trueVal, - UID: containerSourceUID, - }} -} - -// Direct Unit tests. - -func TestObjectNotContainerSource(t *testing.T) { - r := reconciler{} - obj := &corev1.ObjectReference{ - Name: unaddressableName, - Kind: unaddressableKind, - APIVersion: unaddressableAPIVersion, - } + defer logtesting.ClearAll() + table.Test(t, MakeFactory(func(listers *Listers, opt reconciler.Options) controller.Reconciler { + return &Reconciler{ + Base: reconciler.NewBase(opt, controllerAgentName), + containerSourceLister: listers.GetContainerSourceLister(), + deploymentLister: listers.GetDeploymentLister(), + } + })) - got := obj.DeepCopy() - gotErr := r.Reconcile(context.TODO(), got) - var want runtime.Object = obj - if diff := cmp.Diff(want, got); diff != "" { - t.Errorf("unexpected returned object (-want, +got) = %v", diff) - } - if gotErr != nil { - t.Errorf("unexpected returned error %v", gotErr) - } } -func TestObjectHasDeleteTimestamp(t *testing.T) { - r := reconciler{} - obj := getContainerSource() - - now := metav1.Now() - obj.DeletionTimestamp = &now - got := obj.DeepCopy() - gotErr := r.Reconcile(context.TODO(), got) - var want runtime.Object = obj - if diff := cmp.Diff(want, got); diff != "" { - t.Errorf("unexpected returned object (-want, +got) = %v", diff) - } - if gotErr != nil { - t.Errorf("unexpected returned error %v", gotErr) - } -} +// Name: "valid containersource, but sink does not exist", +//Name: "valid containersource, but sink is not addressable", +//Name: "valid containersource, sink is addressable", +//Name: "valid containersource, sink is addressable, fields filled in", +//Name: "valid containersource, sink is Addressable but sink is nil", +//Name: "invalid containersource, sink is nil", +//Name: "valid containersource, sink is provided", +//Name: "valid containersource, labels and annotations given", +//Name: "valid containersource, sink, and deployment", +//Name: "valid containersource, sink, but deployment needs update", +//Name: "Error for create deployment", +//Name: "Error for get source, other than not found", +//Name: "valid containersource, sink is a k8s service", +// +//func getContainerSource() *sourcesv1alpha1.ContainerSource { +// obj := &sourcesv1alpha1.ContainerSource{ +// TypeMeta: containerSourceType(), +// ObjectMeta: om(testNS, containerSourceName), +// Spec: sourcesv1alpha1.ContainerSourceSpec{ +// Image: image, +// Args: []string(nil), +// Sink: &corev1.ObjectReference{ +// Name: addressableName, +// Kind: addressableKind, +// APIVersion: addressableAPIVersion, +// }, +// }, +// } +// // selflink is not filled in when we create the object, so clear it +// obj.ObjectMeta.SelfLink = "" +// return obj +//} +// +//func getContainerSourceFilledIn() *sourcesv1alpha1.ContainerSource { +// obj := getContainerSource() +// obj.ObjectMeta.UID = containerSourceUID +// obj.Spec.Args = []string{"--foo", "bar"} +// obj.Spec.Env = []corev1.EnvVar{{Name: "FOO", Value: "bar"}} +// obj.Spec.ServiceAccountName = "foo" +// return obj +//} +// +//func getContainerSourceSinkService() *sourcesv1alpha1.ContainerSource { +// obj := &sourcesv1alpha1.ContainerSource{ +// TypeMeta: containerSourceType(), +// ObjectMeta: om(testNS, containerSourceName), +// Spec: sourcesv1alpha1.ContainerSourceSpec{ +// Image: image, +// Args: []string(nil), +// Sink: &corev1.ObjectReference{ +// Name: sinkServiceName, +// Kind: sinkServiceKind, +// APIVersion: sinkServiceAPIVersion, +// }, +// }, +// } +// // selflink is not filled in when we create the object, so clear it +// obj.ObjectMeta.SelfLink = "" +// return obj +//} +// +//func getContainerSourceUnaddressable() *sourcesv1alpha1.ContainerSource { +// obj := &sourcesv1alpha1.ContainerSource{ +// TypeMeta: containerSourceType(), +// ObjectMeta: om(testNS, containerSourceName), +// Spec: sourcesv1alpha1.ContainerSourceSpec{ +// Image: image, +// Args: []string{}, +// Sink: &corev1.ObjectReference{ +// Name: unaddressableName, +// Kind: unaddressableKind, +// APIVersion: unaddressableAPIVersion, +// }, +// }, +// } +// // selflink is not filled in when we create the object, so clear it +// obj.ObjectMeta.SelfLink = "" +// return obj +//} +// +//func getAddressable() *unstructured.Unstructured { +// return &unstructured.Unstructured{ +// Object: map[string]interface{}{ +// "apiVersion": addressableAPIVersion, +// "kind": addressableKind, +// "metadata": map[string]interface{}{ +// "namespace": testNS, +// "name": addressableName, +// }, +// "status": map[string]interface{}{ +// "address": map[string]interface{}{ +// "hostname": addressableDNS, +// }, +// }, +// }, +// } +//} +// +//func getAddressableNoStatus() *unstructured.Unstructured { +// return &unstructured.Unstructured{ +// Object: map[string]interface{}{ +// "apiVersion": unaddressableAPIVersion, +// "kind": unaddressableKind, +// "metadata": map[string]interface{}{ +// "namespace": testNS, +// "name": unaddressableName, +// }, +// }, +// } +//} +// +//func getAddressableNilAddress() *unstructured.Unstructured { +// return &unstructured.Unstructured{ +// Object: map[string]interface{}{ +// "apiVersion": addressableAPIVersion, +// "kind": addressableKind, +// "metadata": map[string]interface{}{ +// "namespace": testNS, +// "name": addressableName, +// }, +// "status": map[string]interface{}{ +// "address": map[string]interface{}(nil), +// }, +// }, +// } +//} +// +//func getDeployment(source *sourcesv1alpha1.ContainerSource) *appsv1.Deployment { +// addressableURI := fmt.Sprintf("http://%s/", addressableDNS) +// args := append(source.Spec.Args, fmt.Sprintf("--sink=%s", addressableURI)) +// env := append(source.Spec.Env, corev1.EnvVar{Name: "SINK", Value: addressableURI}) +// return &appsv1.Deployment{ +// TypeMeta: deploymentType(), +// ObjectMeta: metav1.ObjectMeta{ +// GenerateName: fmt.Sprintf("%s-", source.Name), +// Namespace: source.Namespace, +// OwnerReferences: getOwnerReferences(), +// }, +// Spec: appsv1.DeploymentSpec{ +// Selector: &metav1.LabelSelector{ +// MatchLabels: map[string]string{ +// "eventing.knative.dev/source": source.Name, +// }, +// }, +// Template: corev1.PodTemplateSpec{ +// ObjectMeta: metav1.ObjectMeta{ +// Annotations: map[string]string{ +// "sidecar.istio.io/inject": "true", +// }, +// Labels: map[string]string{ +// "eventing.knative.dev/source": source.Name, +// }, +// }, +// Spec: corev1.PodSpec{ +// Containers: []corev1.Container{{ +// Name: "source", +// Image: source.Spec.Image, +// Args: args, +// Env: env, +// ImagePullPolicy: corev1.PullIfNotPresent, +// }}, +// ServiceAccountName: source.Spec.ServiceAccountName, +// }, +// }, +// }, +// } +//} +// +//func containerSourceType() metav1.TypeMeta { +// return metav1.TypeMeta{ +// APIVersion: sourcesv1alpha1.SchemeGroupVersion.String(), +// Kind: "ContainerSource", +// } +//} +// +//func deploymentType() metav1.TypeMeta { +// return metav1.TypeMeta{ +// APIVersion: appsv1.SchemeGroupVersion.String(), +// Kind: "Deployment", +// } +//} +// +//func om(namespace, name string) metav1.ObjectMeta { +// return metav1.ObjectMeta{ +// Namespace: namespace, +// Name: name, +// SelfLink: fmt.Sprintf("/apis/eventing/sources/v1alpha1/namespaces/%s/object/%s", namespace, name), +// } +//} +// +//func getOwnerReferences() []metav1.OwnerReference { +// return []metav1.OwnerReference{{ +// APIVersion: sourcesv1alpha1.SchemeGroupVersion.String(), +// Kind: "ContainerSource", +// Name: containerSourceName, +// Controller: &trueVal, +// BlockOwnerDeletion: &trueVal, +// UID: containerSourceUID, +// }} +//} diff --git a/pkg/reconciler/containersource/resources/deployment.go b/pkg/reconciler/containersource/resources/deployment.go index 7dffe89857f..5664a54dcfb 100644 --- a/pkg/reconciler/containersource/resources/deployment.go +++ b/pkg/reconciler/containersource/resources/deployment.go @@ -28,12 +28,10 @@ import ( const sourceLabelKey = "eventing.knative.dev/source" -func MakeDeployment(org *appsv1.Deployment, args *ContainerArguments) *appsv1.Deployment { +func MakeDeployment(args ContainerArguments) *appsv1.Deployment { + + containerArgs := args.Args - containerArgs := []string(nil) - if args != nil { - containerArgs = args.Args - } // if sink is already in the provided args.Args, don't attempt to add if !args.SinkInArgs { remote := fmt.Sprintf("--sink=%s", args.Sink) @@ -107,7 +105,7 @@ func MakeDeployment(org *appsv1.Deployment, args *ContainerArguments) *appsv1.De return deploy } -func sinkArg(args *ContainerArguments) string { +func sinkArg(args ContainerArguments) string { if args.SinkInArgs { for _, a := range args.Args { if strings.HasPrefix(a, "--sink=") { diff --git a/pkg/reconciler/containersource/resources/deployment_test.go b/pkg/reconciler/containersource/resources/deployment_test.go index 79c82cf6df4..4351008a2dd 100644 --- a/pkg/reconciler/containersource/resources/deployment_test.go +++ b/pkg/reconciler/containersource/resources/deployment_test.go @@ -26,7 +26,7 @@ import ( ) func TestMakeDeployment_sinkoverrideannotationlabelnotallowed(t *testing.T) { - got := MakeDeployment(nil, &ContainerArguments{ + got := MakeDeployment(ContainerArguments{ Name: "test-name", Namespace: "test-namespace", Image: "test-image", @@ -121,7 +121,7 @@ func TestMakeDeployment_sinkoverrideannotationlabelnotallowed(t *testing.T) { } func TestMakeDeployment_sink(t *testing.T) { - got := MakeDeployment(nil, &ContainerArguments{ + got := MakeDeployment(ContainerArguments{ Name: "test-name", Namespace: "test-namespace", Image: "test-image", @@ -206,7 +206,7 @@ func TestMakeDeployment_sink(t *testing.T) { } func TestMakeDeployment_sinkinargs(t *testing.T) { - got := MakeDeployment(nil, &ContainerArguments{ + got := MakeDeployment(ContainerArguments{ Name: "test-name", Namespace: "test-namespace", Image: "test-image", diff --git a/pkg/reconciler/testing/listers.go b/pkg/reconciler/testing/listers.go index 8d634d3a91c..bf17f6dd67f 100644 --- a/pkg/reconciler/testing/listers.go +++ b/pkg/reconciler/testing/listers.go @@ -120,6 +120,10 @@ func (l *Listers) GetCronJobSourceLister() sourcelisters.CronJobSourceLister { return sourcelisters.NewCronJobSourceLister(l.indexerFor(&sourcesv1alpha1.CronJobSource{})) } +func (l *Listers) GetContainerSourceLister() sourcelisters.ContainerSourceLister { + return sourcelisters.NewContainerSourceLister(l.indexerFor(&sourcesv1alpha1.ContainerSource{})) +} + // GetGatewayLister gets lister for Istio Gateway resource. func (l *Listers) GetGatewayLister() istiolisters.GatewayLister { return istiolisters.NewGatewayLister(l.indexerFor(&istiov1alpha3.Gateway{})) From 383690b140c7d5093892d1750e850980af234867 Mon Sep 17 00:00:00 2001 From: Scott Nichols Date: Thu, 25 Apr 2019 08:52:41 -0700 Subject: [PATCH 22/25] first test. --- .../containersource/containersource_test.go | 31 +++++++- pkg/reconciler/testing/containersource.go | 75 +++++++++++++++++++ 2 files changed, 104 insertions(+), 2 deletions(-) create mode 100644 pkg/reconciler/testing/containersource.go diff --git a/pkg/reconciler/containersource/containersource_test.go b/pkg/reconciler/containersource/containersource_test.go index e2052340883..8607f7981c5 100644 --- a/pkg/reconciler/containersource/containersource_test.go +++ b/pkg/reconciler/containersource/containersource_test.go @@ -18,9 +18,10 @@ package containersource import ( "github.com/knative/eventing/pkg/utils" + "k8s.io/apimachinery/pkg/runtime" "testing" - //clientgotesting "k8s.io/client-go/testing" + clientgotesting "k8s.io/client-go/testing" fakeclientset "github.com/knative/eventing/pkg/client/clientset/versioned/fake" informers "github.com/knative/eventing/pkg/client/informers/externalversions" @@ -38,7 +39,7 @@ import ( . "github.com/knative/eventing/pkg/reconciler/testing" . "github.com/knative/pkg/reconciler/testing" - //sourcesv1alpha1 "github.com/knative/eventing/pkg/apis/sources/v1alpha1" + sourcesv1alpha1 "github.com/knative/eventing/pkg/apis/sources/v1alpha1" v1 "k8s.io/api/apps/v1" ) @@ -125,6 +126,32 @@ func TestAllCases(t *testing.T) { Name: "key not found", // Make sure Reconcile handles good keys that don't exist. Key: "foo/not-found", + }, { + Name: "missing sink", + Objects: []runtime.Object{ + NewContainerSource(sourceName, testNS, + WithContainerSourceSpec(sourcesv1alpha1.ContainerSourceSpec{ + Image: image, + Sink: &sinkRef, + }), + ), + }, + Key: testNS + "/" + sourceName, + WantErr: true, + WantEvents: []string{ + Eventf(corev1.EventTypeWarning, "SetSinkURIFailed", `Failed to set Sink URI: channels.eventing.knative.dev "testsink" not found`), + }, + WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ + Object: NewContainerSource(sourceName, testNS, + WithContainerSourceSpec(sourcesv1alpha1.ContainerSourceSpec{ + Image: image, + Sink: &sinkRef, + }), + // Status Update: + WithInitContainerSourceConditions, + WithContainerSourceSinkNotFound(`Couldn't get Sink URI from "/testsink": channels.eventing.knative.dev "testsink" not found"`), + ), + }}, }, } diff --git a/pkg/reconciler/testing/containersource.go b/pkg/reconciler/testing/containersource.go new file mode 100644 index 00000000000..f7991327e14 --- /dev/null +++ b/pkg/reconciler/testing/containersource.go @@ -0,0 +1,75 @@ +/* +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 ( + "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/knative/eventing/pkg/apis/sources/v1alpha1" +) + +// ContainerSourceOption enables further configuration of a CronJob. +type ContainerSourceOption func(*v1alpha1.ContainerSource) + +// NewCronJob creates a CronJob with CronJobOptions +func NewContainerSource(name, namespace string, o ...ContainerSourceOption) *v1alpha1.ContainerSource { + c := &v1alpha1.ContainerSource{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + }, + } + for _, opt := range o { + opt(c) + } + //c.SetDefaults(context.Background()) // TODO: We should add defaults and validation. + return c +} + +// WithInitContainerSourceConditions initializes the ContainerSource's conditions. +func WithInitContainerSourceConditions(s *v1alpha1.ContainerSource) { + s.Status.InitializeConditions() +} + +func WithContainerSourceSinkNotFound(msg string) ContainerSourceOption { + return func(s *v1alpha1.ContainerSource) { + s.Status.MarkNoSink("NotFound", msg) + } +} + +func WithContainerSourceSink(uri string) ContainerSourceOption { + return func(s *v1alpha1.ContainerSource) { + s.Status.MarkSink(uri) + } +} + +func WithContainerSourceDeployed(s *v1alpha1.ContainerSource) { + s.Status.MarkDeployed() +} + +func WithContainerSourceDeleted(c *v1alpha1.ContainerSource) { + t := metav1.NewTime(time.Unix(1e9, 0)) + c.ObjectMeta.SetDeletionTimestamp(&t) +} + +func WithContainerSourceSpec(spec v1alpha1.ContainerSourceSpec) ContainerSourceOption { + return func(c *v1alpha1.ContainerSource) { + c.Spec = spec + } +} From b800653ee34d631a1d6df261028ce4fa99ec8c70 Mon Sep 17 00:00:00 2001 From: Scott Nichols Date: Thu, 25 Apr 2019 10:41:06 -0700 Subject: [PATCH 23/25] more tests. --- .../containersource/containersource_test.go | 298 ++++++++++++------ .../cronjobsource/cronjobsource_test.go | 6 +- pkg/reconciler/testing/containersource.go | 12 + 3 files changed, 223 insertions(+), 93 deletions(-) diff --git a/pkg/reconciler/containersource/containersource_test.go b/pkg/reconciler/containersource/containersource_test.go index 8607f7981c5..2e6e945ecd5 100644 --- a/pkg/reconciler/containersource/containersource_test.go +++ b/pkg/reconciler/containersource/containersource_test.go @@ -17,6 +17,7 @@ limitations under the License. package containersource import ( + "fmt" "github.com/knative/eventing/pkg/utils" "k8s.io/apimachinery/pkg/runtime" "testing" @@ -29,8 +30,9 @@ import ( duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" "github.com/knative/pkg/controller" logtesting "github.com/knative/pkg/logging/testing" + appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" - //metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" //"k8s.io/apimachinery/pkg/runtime" kubeinformers "k8s.io/client-go/informers" fakekubeclientset "k8s.io/client-go/kubernetes/fake" @@ -48,7 +50,6 @@ const ( sourceName = "test-container-source" sourceUID = "1234-5678-90" testNS = "testnamespace" - testData = "data" sinkName = "testsink" ) @@ -61,29 +62,35 @@ var ( Kind: "Channel", APIVersion: "eventing.knative.dev/v1alpha1", } + nonsinkRef = corev1.ObjectReference{ + Name: sinkName, + Kind: "Trigger", + APIVersion: "eventing.knative.dev/v1alpha1", + } sinkDNS = "sink.mynamespace.svc." + utils.GetClusterDomainName() sinkURI = "http://" + sinkDNS + "/" ) -const ( - containerSourceName = "testcontainersource" - containerSourceUID = "2a2208d1-ce67-11e8-b3a3-42010a8a00af" - deployGeneratedName = "" //sad trombone - - addressableDNS = "addressable.sink.svc.cluster.local" - - addressableName = "testsink" - addressableKind = "Sink" - addressableAPIVersion = "duck.knative.dev/v1alpha1" - - unaddressableName = "testunaddressable" - unaddressableKind = "KResource" - unaddressableAPIVersion = "duck.knative.dev/v1alpha1" - - sinkServiceName = "testsinkservice" - sinkServiceKind = "Service" - sinkServiceAPIVersion = "v1" -) +// +//const ( +// containerSourceName = "testcontainersource" +// containerSourceUID = "2a2208d1-ce67-11e8-b3a3-42010a8a00af" +// deployGeneratedName = "" //sad trombone +// +// addressableDNS = "addressable.sink.svc.cluster.local" +// +// addressableName = "testsink" +// addressableKind = "Sink" +// addressableAPIVersion = "duck.knative.dev/v1alpha1" +// +// unaddressableName = "testunaddressable" +// unaddressableKind = "KResource" +// unaddressableAPIVersion = "duck.knative.dev/v1alpha1" +// +// sinkServiceName = "testsinkservice" +// sinkServiceKind = "Service" +// sinkServiceAPIVersion = "v1" +//) func init() { // Add types to scheme @@ -152,7 +159,130 @@ func TestAllCases(t *testing.T) { WithContainerSourceSinkNotFound(`Couldn't get Sink URI from "/testsink": channels.eventing.knative.dev "testsink" not found"`), ), }}, + }, { + Name: "sink not addressable", + Objects: []runtime.Object{ + NewContainerSource(sourceName, testNS, + WithContainerSourceSpec(sourcesv1alpha1.ContainerSourceSpec{ + Image: image, + Sink: &nonsinkRef, + }), + ), + NewTrigger(sinkName, testNS, ""), + }, + Key: testNS + "/" + sourceName, + WantErr: true, + WantEvents: []string{ + Eventf(corev1.EventTypeWarning, "SetSinkURIFailed", `Failed to set Sink URI: sink "testnamespace/testsink" (eventing.knative.dev/v1alpha1, Kind=Trigger) does not contain address`), + }, + WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ + Object: NewContainerSource(sourceName, testNS, + WithContainerSourceSpec(sourcesv1alpha1.ContainerSourceSpec{ + Image: image, + Sink: &nonsinkRef, + }), + // Status Update: + WithInitContainerSourceConditions, + WithContainerSourceSinkNotFound(`Couldn't get Sink URI from "/testsink": sink "testnamespace/testsink" (eventing.knative.dev/v1alpha1, Kind=Trigger) does not contain address"`), + ), + }}, + }, { + Name: "sink not ready", + Objects: []runtime.Object{ + NewContainerSource(sourceName, testNS, + WithContainerSourceSpec(sourcesv1alpha1.ContainerSourceSpec{ + Image: image, + Sink: &sinkRef, + }), + ), + NewChannel(sinkName, testNS), + }, + Key: testNS + "/" + sourceName, + WantErr: true, + WantEvents: []string{ + Eventf(corev1.EventTypeWarning, "SetSinkURIFailed", `Failed to set Sink URI: sink "testnamespace/testsink" (eventing.knative.dev/v1alpha1, Kind=Channel) contains an empty hostname`), + }, + WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ + Object: NewContainerSource(sourceName, testNS, + WithContainerSourceSpec(sourcesv1alpha1.ContainerSourceSpec{ + Image: image, + Sink: &sinkRef, + }), + // Status Update: + WithInitContainerSourceConditions, + WithContainerSourceSinkNotFound(`Couldn't get Sink URI from "/testsink": sink "testnamespace/testsink" (eventing.knative.dev/v1alpha1, Kind=Channel) contains an empty hostname"`), + ), + }}, + }, { + Name: "sink is nil", + Objects: []runtime.Object{ + NewContainerSource(sourceName, testNS, + WithContainerSourceSpec(sourcesv1alpha1.ContainerSourceSpec{ + Image: image, + }), + ), + }, + Key: testNS + "/" + sourceName, + WantErr: true, + WantEvents: []string{ + Eventf(corev1.EventTypeWarning, "SetSinkURIFailed", `Failed to set Sink URI: Sink missing from spec`), + }, + WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ + Object: NewContainerSource(sourceName, testNS, + WithContainerSourceSpec(sourcesv1alpha1.ContainerSourceSpec{ + Image: image, + }), + // Status Update: + WithInitContainerSourceConditions, + WithContainerSourceSinkMissing("Sink missing from spec"), + ), + }}, + }, { + Name: "valid", + Objects: []runtime.Object{ + NewContainerSource(sourceName, testNS, + WithContainerSourceSpec(sourcesv1alpha1.ContainerSourceSpec{ + Image: image, + Sink: &sinkRef, + }), + ), + NewChannel(sinkName, testNS, + WithChannelAddress(sinkDNS), + ), + }, + Key: testNS + "/" + sourceName, + WantEvents: []string{ + Eventf(corev1.EventTypeNormal, "DeploymentCreated", `Created deployment ""`), // TODO on noes + Eventf(corev1.EventTypeNormal, "ContainerSourceReconciled", `ContainerSource reconciled: "testnamespace/test-container-source"`), + }, + WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ + Object: NewContainerSource(sourceName, testNS, + WithContainerSourceSpec(sourcesv1alpha1.ContainerSourceSpec{ + Image: image, + Sink: &sinkRef, + }), + // Status Update: + WithInitContainerSourceConditions, + WithContainerSourceSink(sinkURI), + WithContainerSourceDeploying(`Created deployment ""`), + ), + }}, + WantCreates: []metav1.Object{ + makeDeployment(NewContainerSource(sourceName, testNS, + WithContainerSourceSpec(sourcesv1alpha1.ContainerSourceSpec{ + Image: image, + }))), + }, }, + + //Name: "valid containersource, sink is provided", + //Name: "valid containersource, labels and annotations given", + //Name: "valid containersource, sink, and deployment", + //Name: "valid containersource, sink, but deployment needs update", + //Name: "Error for create deployment", + //Name: "Error for get source, other than not found", + //Name: "valid containersource, sink is a k8s service", + } defer logtesting.ClearAll() @@ -166,19 +296,6 @@ func TestAllCases(t *testing.T) { } -// Name: "valid containersource, but sink does not exist", -//Name: "valid containersource, but sink is not addressable", -//Name: "valid containersource, sink is addressable", -//Name: "valid containersource, sink is addressable, fields filled in", -//Name: "valid containersource, sink is Addressable but sink is nil", -//Name: "invalid containersource, sink is nil", -//Name: "valid containersource, sink is provided", -//Name: "valid containersource, labels and annotations given", -//Name: "valid containersource, sink, and deployment", -//Name: "valid containersource, sink, but deployment needs update", -//Name: "Error for create deployment", -//Name: "Error for get source, other than not found", -//Name: "valid containersource, sink is a k8s service", // //func getContainerSource() *sourcesv1alpha1.ContainerSource { // obj := &sourcesv1alpha1.ContainerSource{ @@ -293,46 +410,46 @@ func TestAllCases(t *testing.T) { // } //} // -//func getDeployment(source *sourcesv1alpha1.ContainerSource) *appsv1.Deployment { -// addressableURI := fmt.Sprintf("http://%s/", addressableDNS) -// args := append(source.Spec.Args, fmt.Sprintf("--sink=%s", addressableURI)) -// env := append(source.Spec.Env, corev1.EnvVar{Name: "SINK", Value: addressableURI}) -// return &appsv1.Deployment{ -// TypeMeta: deploymentType(), -// ObjectMeta: metav1.ObjectMeta{ -// GenerateName: fmt.Sprintf("%s-", source.Name), -// Namespace: source.Namespace, -// OwnerReferences: getOwnerReferences(), -// }, -// Spec: appsv1.DeploymentSpec{ -// Selector: &metav1.LabelSelector{ -// MatchLabels: map[string]string{ -// "eventing.knative.dev/source": source.Name, -// }, -// }, -// Template: corev1.PodTemplateSpec{ -// ObjectMeta: metav1.ObjectMeta{ -// Annotations: map[string]string{ -// "sidecar.istio.io/inject": "true", -// }, -// Labels: map[string]string{ -// "eventing.knative.dev/source": source.Name, -// }, -// }, -// Spec: corev1.PodSpec{ -// Containers: []corev1.Container{{ -// Name: "source", -// Image: source.Spec.Image, -// Args: args, -// Env: env, -// ImagePullPolicy: corev1.PullIfNotPresent, -// }}, -// ServiceAccountName: source.Spec.ServiceAccountName, -// }, -// }, -// }, -// } -//} +func makeDeployment(source *sourcesv1alpha1.ContainerSource) *appsv1.Deployment { + args := append(source.Spec.Args, fmt.Sprintf("--sink=%s", sinkURI)) + env := append(source.Spec.Env, corev1.EnvVar{Name: "SINK", Value: sinkURI}) + return &appsv1.Deployment{ + TypeMeta: deploymentType(), + ObjectMeta: metav1.ObjectMeta{ + GenerateName: fmt.Sprintf("%s-", source.Name), + Namespace: source.Namespace, + OwnerReferences: getOwnerReferences(), + }, + Spec: appsv1.DeploymentSpec{ + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "eventing.knative.dev/source": source.Name, + }, + }, + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + "sidecar.istio.io/inject": "true", + }, + Labels: map[string]string{ + "eventing.knative.dev/source": source.Name, + }, + }, + Spec: corev1.PodSpec{ + Containers: []corev1.Container{{ + Name: "source", + Image: source.Spec.Image, + Args: args, + Env: env, + ImagePullPolicy: corev1.PullIfNotPresent, + }}, + ServiceAccountName: source.Spec.ServiceAccountName, + }, + }, + }, + } +} + // //func containerSourceType() metav1.TypeMeta { // return metav1.TypeMeta{ @@ -341,12 +458,13 @@ func TestAllCases(t *testing.T) { // } //} // -//func deploymentType() metav1.TypeMeta { -// return metav1.TypeMeta{ -// APIVersion: appsv1.SchemeGroupVersion.String(), -// Kind: "Deployment", -// } -//} +func deploymentType() metav1.TypeMeta { + return metav1.TypeMeta{ + APIVersion: appsv1.SchemeGroupVersion.String(), + Kind: "Deployment", + } +} + // //func om(namespace, name string) metav1.ObjectMeta { // return metav1.ObjectMeta{ @@ -356,13 +474,13 @@ func TestAllCases(t *testing.T) { // } //} // -//func getOwnerReferences() []metav1.OwnerReference { -// return []metav1.OwnerReference{{ -// APIVersion: sourcesv1alpha1.SchemeGroupVersion.String(), -// Kind: "ContainerSource", -// Name: containerSourceName, -// Controller: &trueVal, -// BlockOwnerDeletion: &trueVal, -// UID: containerSourceUID, -// }} -//} +func getOwnerReferences() []metav1.OwnerReference { + return []metav1.OwnerReference{{ + APIVersion: sourcesv1alpha1.SchemeGroupVersion.String(), + Kind: "ContainerSource", + Name: sourceName, + Controller: &trueVal, + BlockOwnerDeletion: &trueVal, + UID: sourceUID, + }} +} diff --git a/pkg/reconciler/cronjobsource/cronjobsource_test.go b/pkg/reconciler/cronjobsource/cronjobsource_test.go index a971cb1e4e9..a07e6f9c6f8 100644 --- a/pkg/reconciler/cronjobsource/cronjobsource_test.go +++ b/pkg/reconciler/cronjobsource/cronjobsource_test.go @@ -42,7 +42,7 @@ import ( . "github.com/knative/pkg/reconciler/testing" sourcesv1alpha1 "github.com/knative/eventing/pkg/apis/sources/v1alpha1" - v1 "k8s.io/api/apps/v1" + appsv1 "k8s.io/api/apps/v1" ) var ( @@ -79,7 +79,7 @@ const ( func init() { // Add types to scheme - _ = v1.AddToScheme(scheme.Scheme) + _ = appsv1.AddToScheme(scheme.Scheme) _ = corev1.AddToScheme(scheme.Scheme) _ = duckv1alpha1.AddToScheme(scheme.Scheme) @@ -282,7 +282,7 @@ func TestNew(t *testing.T) { } } -func makeReceiveAdapter() *v1.Deployment { +func makeReceiveAdapter() *appsv1.Deployment { source := NewCronSourceJob(sourceName, testNS, WithCronJobSourceSpec(sourcesv1alpha1.CronJobSourceSpec{ Schedule: testSchedule, diff --git a/pkg/reconciler/testing/containersource.go b/pkg/reconciler/testing/containersource.go index f7991327e14..809832ff869 100644 --- a/pkg/reconciler/testing/containersource.go +++ b/pkg/reconciler/testing/containersource.go @@ -53,12 +53,24 @@ func WithContainerSourceSinkNotFound(msg string) ContainerSourceOption { } } +func WithContainerSourceSinkMissing(msg string) ContainerSourceOption { + return func(s *v1alpha1.ContainerSource) { + s.Status.MarkNoSink("Missing", msg) + } +} + func WithContainerSourceSink(uri string) ContainerSourceOption { return func(s *v1alpha1.ContainerSource) { s.Status.MarkSink(uri) } } +func WithContainerSourceDeploying(msg string) ContainerSourceOption { + return func(s *v1alpha1.ContainerSource) { + s.Status.MarkDeploying("DeploymentCreated", msg) + } +} + func WithContainerSourceDeployed(s *v1alpha1.ContainerSource) { s.Status.MarkDeployed() } From 3ce27b6dc6c0c0f9275b632aff94e61935fcded0 Mon Sep 17 00:00:00 2001 From: Scott Nichols Date: Thu, 25 Apr 2019 13:22:51 -0700 Subject: [PATCH 24/25] working tests. --- cmd/sources-controller/main.go | 16 +- .../containersource/containersource.go | 7 +- .../containersource/containersource_test.go | 409 +++++++++--------- .../resources/deployment_test.go | 37 ++ .../cronjobsource/cronjobsource_test.go | 34 +- pkg/reconciler/testing/containersource.go | 25 ++ 6 files changed, 306 insertions(+), 222 deletions(-) diff --git a/cmd/sources-controller/main.go b/cmd/sources-controller/main.go index 6abe075e348..000cbf04c4a 100644 --- a/cmd/sources-controller/main.go +++ b/cmd/sources-controller/main.go @@ -18,6 +18,7 @@ package main import ( "flag" + "github.com/knative/eventing/pkg/reconciler/containersource" "k8s.io/client-go/tools/clientcmd" "log" @@ -63,7 +64,7 @@ func main() { logger = logger.With(zap.String("controller/impl", "pkg")) logger.Info("Starting the controller") - const numControllers = 1 + const numControllers = 2 cfg.QPS = numControllers * rest.DefaultQPS cfg.Burst = numControllers * rest.DefaultBurst opt := reconciler.NewOptionsOrDie(cfg, logger, stopCh) @@ -72,7 +73,8 @@ func main() { eventingInformerFactory := informers.NewSharedInformerFactory(opt.EventingClientSet, opt.ResyncPeriod) // Eventing - cronjobsourceInformer := eventingInformerFactory.Sources().V1alpha1().CronJobSources() + cronJobSourceInformer := eventingInformerFactory.Sources().V1alpha1().CronJobSources() + containerSourceInformer := eventingInformerFactory.Sources().V1alpha1().ContainerSources() // Kube deploymentInformer := kubeInformerFactory.Apps().V1().Deployments() @@ -83,7 +85,12 @@ func main() { controllers := []*kncontroller.Impl{ cronjobsource.NewController( opt, - cronjobsourceInformer, + cronJobSourceInformer, + deploymentInformer, + ), + containersource.NewController( + opt, + containerSourceInformer, deploymentInformer, ), } @@ -104,7 +111,8 @@ func main() { if err := kncontroller.StartInformers( stopCh, // Eventing - cronjobsourceInformer.Informer(), + cronJobSourceInformer.Informer(), + containerSourceInformer.Informer(), // Kube deploymentInformer.Informer(), ); err != nil { diff --git a/pkg/reconciler/containersource/containersource.go b/pkg/reconciler/containersource/containersource.go index 6d91e8a7e77..9535349ee7a 100644 --- a/pkg/reconciler/containersource/containersource.go +++ b/pkg/reconciler/containersource/containersource.go @@ -182,7 +182,7 @@ func (r *Reconciler) reconcile(ctx context.Context, source *v1alpha1.ContainerSo if errors.IsNotFound(err) { deploy, err = r.createDeployment(ctx, source, nil, args) if err != nil { - r.markDeployingAndRecordEvent(source, corev1.EventTypeWarning, "DeploymentCreateFailed", "Could not create deployment: %v", err) + r.markNotDeployedRecordEvent(source, corev1.EventTypeWarning, "DeploymentCreateFailed", "Could not create deployment: %v", err) return err } r.markDeployingAndRecordEvent(source, corev1.EventTypeNormal, "DeploymentCreated", "Created deployment %q", deploy.Name) @@ -283,6 +283,11 @@ func (r *Reconciler) markDeployingAndRecordEvent(source *v1alpha1.ContainerSourc source.Status.MarkDeploying(reason, messageFmt, args...) } +func (r *Reconciler) markNotDeployedRecordEvent(source *v1alpha1.ContainerSource, evType string, reason string, messageFmt string, args ...interface{}) { + r.Recorder.Eventf(source, evType, reason, messageFmt, args...) + source.Status.MarkNotDeployed(reason, messageFmt, args...) +} + func (r *Reconciler) updateStatus(ctx context.Context, desired *v1alpha1.ContainerSource) (*v1alpha1.ContainerSource, error) { source, err := r.containerSourceLister.ContainerSources(desired.Namespace).Get(desired.Name) if err != nil { diff --git a/pkg/reconciler/containersource/containersource_test.go b/pkg/reconciler/containersource/containersource_test.go index 2e6e945ecd5..eb5a9d8b02b 100644 --- a/pkg/reconciler/containersource/containersource_test.go +++ b/pkg/reconciler/containersource/containersource_test.go @@ -18,31 +18,28 @@ package containersource import ( "fmt" - "github.com/knative/eventing/pkg/utils" - "k8s.io/apimachinery/pkg/runtime" "testing" + 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" + kubeinformers "k8s.io/client-go/informers" + fakekubeclientset "k8s.io/client-go/kubernetes/fake" + "k8s.io/client-go/kubernetes/scheme" clientgotesting "k8s.io/client-go/testing" + sourcesv1alpha1 "github.com/knative/eventing/pkg/apis/sources/v1alpha1" fakeclientset "github.com/knative/eventing/pkg/client/clientset/versioned/fake" informers "github.com/knative/eventing/pkg/client/informers/externalversions" "github.com/knative/eventing/pkg/reconciler" + "github.com/knative/eventing/pkg/utils" duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" "github.com/knative/pkg/controller" logtesting "github.com/knative/pkg/logging/testing" - 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" - kubeinformers "k8s.io/client-go/informers" - fakekubeclientset "k8s.io/client-go/kubernetes/fake" - "k8s.io/client-go/kubernetes/scheme" . "github.com/knative/eventing/pkg/reconciler/testing" . "github.com/knative/pkg/reconciler/testing" - - sourcesv1alpha1 "github.com/knative/eventing/pkg/apis/sources/v1alpha1" - v1 "k8s.io/api/apps/v1" ) const ( @@ -54,8 +51,7 @@ const ( ) var ( - trueVal = true - targetURI = "http://addressable.sink.svc.cluster.local/" + trueVal = true sinkRef = corev1.ObjectReference{ Name: sinkName, @@ -69,32 +65,19 @@ var ( } sinkDNS = "sink.mynamespace.svc." + utils.GetClusterDomainName() sinkURI = "http://" + sinkDNS + "/" -) -// -//const ( -// containerSourceName = "testcontainersource" -// containerSourceUID = "2a2208d1-ce67-11e8-b3a3-42010a8a00af" -// deployGeneratedName = "" //sad trombone -// -// addressableDNS = "addressable.sink.svc.cluster.local" -// -// addressableName = "testsink" -// addressableKind = "Sink" -// addressableAPIVersion = "duck.knative.dev/v1alpha1" -// -// unaddressableName = "testunaddressable" -// unaddressableKind = "KResource" -// unaddressableAPIVersion = "duck.knative.dev/v1alpha1" -// -// sinkServiceName = "testsinkservice" -// sinkServiceKind = "Service" -// sinkServiceAPIVersion = "v1" -//) + // TODO: k8s service does not work, fix. + //serviceRef = corev1.ObjectReference{ + // Name: sinkName, + // Kind: "Service", + // APIVersion: "v1", + //} + //serviceURI = "http://service.sink.svc.cluster.local/" +) func init() { // Add types to scheme - _ = v1.AddToScheme(scheme.Scheme) + _ = appsv1.AddToScheme(scheme.Scheme) _ = corev1.AddToScheme(scheme.Scheme) _ = duckv1alpha1.AddToScheme(scheme.Scheme) } @@ -238,13 +221,14 @@ func TestAllCases(t *testing.T) { ), }}, }, { - Name: "valid", + Name: "valid first pass", Objects: []runtime.Object{ NewContainerSource(sourceName, testNS, WithContainerSourceSpec(sourcesv1alpha1.ContainerSourceSpec{ Image: image, Sink: &sinkRef, }), + WithContainerSourceUID(sourceUID), ), NewChannel(sinkName, testNS, WithChannelAddress(sinkDNS), @@ -261,6 +245,7 @@ func TestAllCases(t *testing.T) { Image: image, Sink: &sinkRef, }), + WithContainerSourceUID(sourceUID), // Status Update: WithInitContainerSourceConditions, WithContainerSourceSink(sinkURI), @@ -271,18 +256,177 @@ func TestAllCases(t *testing.T) { makeDeployment(NewContainerSource(sourceName, testNS, WithContainerSourceSpec(sourcesv1alpha1.ContainerSourceSpec{ Image: image, - }))), + }), + WithContainerSourceUID(sourceUID), + ), 0, nil, nil), + }, + }, { + Name: "valid, with ready deployment", + Objects: []runtime.Object{ + NewContainerSource(sourceName, testNS, + WithContainerSourceSpec(sourcesv1alpha1.ContainerSourceSpec{ + Image: image, + Sink: &sinkRef, + }), + WithContainerSourceUID(sourceUID), + WithInitContainerSourceConditions, + WithContainerSourceSink(sinkURI), + WithContainerSourceDeploying(`Created deployment ""`), + ), + NewChannel(sinkName, testNS, + WithChannelAddress(sinkDNS), + ), + makeDeployment(NewContainerSource(sourceName, testNS, + WithContainerSourceSpec(sourcesv1alpha1.ContainerSourceSpec{ + Image: image, + }), + WithContainerSourceUID(sourceUID), + ), 1, nil, nil), + }, + Key: testNS + "/" + sourceName, + WantEvents: []string{ + Eventf(corev1.EventTypeNormal, "DeploymentReady", `Deployment "" has 1 ready replicas`), + Eventf(corev1.EventTypeNormal, "ContainerSourceReconciled", `ContainerSource reconciled: "testnamespace/test-container-source"`), + }, + WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ + Object: NewContainerSource(sourceName, testNS, + WithContainerSourceSpec(sourcesv1alpha1.ContainerSourceSpec{ + Image: image, + Sink: &sinkRef, + }), + WithContainerSourceUID(sourceUID), + WithInitContainerSourceConditions, + WithContainerSourceSink(sinkURI), + // Status Update: + WithContainerSourceDeployed, + ), + }}, + }, { + Name: "valid first pass, with annotations and labels", + Objects: []runtime.Object{ + NewContainerSource(sourceName, testNS, + WithContainerSourceSpec(sourcesv1alpha1.ContainerSourceSpec{ + Image: image, + Sink: &sinkRef, + }), + WithContainerSourceUID(sourceUID), + WithContainerSourceLabels(map[string]string{"label": "labeled"}), + WithContainerSourceAnnotations(map[string]string{"annotation": "annotated"}), + ), + NewChannel(sinkName, testNS, + WithChannelAddress(sinkDNS), + ), + }, + Key: testNS + "/" + sourceName, + WantEvents: []string{ + Eventf(corev1.EventTypeNormal, "DeploymentCreated", `Created deployment ""`), // TODO on noes + Eventf(corev1.EventTypeNormal, "ContainerSourceReconciled", `ContainerSource reconciled: "testnamespace/test-container-source"`), + }, + WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ + Object: NewContainerSource(sourceName, testNS, + WithContainerSourceSpec(sourcesv1alpha1.ContainerSourceSpec{ + Image: image, + Sink: &sinkRef, + }), + WithContainerSourceUID(sourceUID), + WithContainerSourceLabels(map[string]string{"label": "labeled"}), + WithContainerSourceAnnotations(map[string]string{"annotation": "annotated"}), + // Status Update: + WithInitContainerSourceConditions, + WithContainerSourceSink(sinkURI), + WithContainerSourceDeploying(`Created deployment ""`), + ), + }}, + WantCreates: []metav1.Object{ + makeDeployment(NewContainerSource(sourceName, testNS, + WithContainerSourceSpec(sourcesv1alpha1.ContainerSourceSpec{ + Image: image, + }), + WithContainerSourceUID(sourceUID), + ), 0, map[string]string{"label": "labeled"}, map[string]string{"annotation": "annotated"}), + }, + }, { + Name: "error for create deployment", + Objects: []runtime.Object{ + NewContainerSource(sourceName, testNS, + WithContainerSourceSpec(sourcesv1alpha1.ContainerSourceSpec{ + Image: image, + Sink: &sinkRef, + }), + WithContainerSourceUID(sourceUID), + ), + NewChannel(sinkName, testNS, + WithChannelAddress(sinkDNS), + ), + }, + Key: testNS + "/" + sourceName, + WantErr: true, + WantEvents: []string{ + Eventf(corev1.EventTypeWarning, "DeploymentCreateFailed", "Could not create deployment: inducing failure for create deployments"), + }, + WithReactors: []clientgotesting.ReactionFunc{ + InduceFailure("create", "deployments"), + }, + WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ + Object: NewContainerSource(sourceName, testNS, + WithContainerSourceSpec(sourcesv1alpha1.ContainerSourceSpec{ + Image: image, + Sink: &sinkRef, + }), + WithContainerSourceUID(sourceUID), + // Status Update: + WithInitContainerSourceConditions, + WithContainerSourceSink(sinkURI), + WithContainerSourceDeployFailed(`Could not create deployment: inducing failure for create deployments`), + ), + }}, + WantCreates: []metav1.Object{ + makeDeployment(NewContainerSource(sourceName, testNS, + WithContainerSourceSpec(sourcesv1alpha1.ContainerSourceSpec{ + Image: image, + }), + WithContainerSourceUID(sourceUID), + ), 0, nil, nil), }, }, - - //Name: "valid containersource, sink is provided", - //Name: "valid containersource, labels and annotations given", - //Name: "valid containersource, sink, and deployment", - //Name: "valid containersource, sink, but deployment needs update", - //Name: "Error for create deployment", - //Name: "Error for get source, other than not found", - //Name: "valid containersource, sink is a k8s service", - + //{ // TODO: k8s service does not work, fix. + // Name: "valid, with sink as service", + // Objects: []runtime.Object{ + // NewContainerSource(sourceName, testNS, + // WithContainerSourceSpec(sourcesv1alpha1.ContainerSourceSpec{ + // Image: image, + // Sink: &serviceRef, + // }), + // WithContainerSourceUID(sourceUID), + // ), + // NewService(sinkName, testNS), + // }, + // Key: testNS + "/" + sourceName, + // WantEvents: []string{ + // Eventf(corev1.EventTypeNormal, "ContainerSourceReconciled", `ContainerSource reconciled: "testnamespace/test-container-source"`), + // }, + // WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ + // Object: NewContainerSource(sourceName, testNS, + // WithContainerSourceSpec(sourcesv1alpha1.ContainerSourceSpec{ + // Image: image, + // Sink: &serviceRef, + // }), + // WithContainerSourceUID(sourceUID), + // // Status Update: + // WithInitContainerSourceConditions, + // WithContainerSourceSink(serviceURI), + // WithContainerSourceDeploying(`Created deployment ""`), + // ), + // }}, + // WantCreates: []metav1.Object{ + // makeDeployment(NewContainerSource(sourceName, testNS, + // WithContainerSourceSpec(sourcesv1alpha1.ContainerSourceSpec{ + // Image: image, + // }), + // WithContainerSourceUID(sourceUID), + // ), 0), + // }, + //}, } defer logtesting.ClearAll() @@ -296,125 +440,29 @@ func TestAllCases(t *testing.T) { } -// -//func getContainerSource() *sourcesv1alpha1.ContainerSource { -// obj := &sourcesv1alpha1.ContainerSource{ -// TypeMeta: containerSourceType(), -// ObjectMeta: om(testNS, containerSourceName), -// Spec: sourcesv1alpha1.ContainerSourceSpec{ -// Image: image, -// Args: []string(nil), -// Sink: &corev1.ObjectReference{ -// Name: addressableName, -// Kind: addressableKind, -// APIVersion: addressableAPIVersion, -// }, -// }, -// } -// // selflink is not filled in when we create the object, so clear it -// obj.ObjectMeta.SelfLink = "" -// return obj -//} -// -//func getContainerSourceFilledIn() *sourcesv1alpha1.ContainerSource { -// obj := getContainerSource() -// obj.ObjectMeta.UID = containerSourceUID -// obj.Spec.Args = []string{"--foo", "bar"} -// obj.Spec.Env = []corev1.EnvVar{{Name: "FOO", Value: "bar"}} -// obj.Spec.ServiceAccountName = "foo" -// return obj -//} -// -//func getContainerSourceSinkService() *sourcesv1alpha1.ContainerSource { -// obj := &sourcesv1alpha1.ContainerSource{ -// TypeMeta: containerSourceType(), -// ObjectMeta: om(testNS, containerSourceName), -// Spec: sourcesv1alpha1.ContainerSourceSpec{ -// Image: image, -// Args: []string(nil), -// Sink: &corev1.ObjectReference{ -// Name: sinkServiceName, -// Kind: sinkServiceKind, -// APIVersion: sinkServiceAPIVersion, -// }, -// }, -// } -// // selflink is not filled in when we create the object, so clear it -// obj.ObjectMeta.SelfLink = "" -// return obj -//} -// -//func getContainerSourceUnaddressable() *sourcesv1alpha1.ContainerSource { -// obj := &sourcesv1alpha1.ContainerSource{ -// TypeMeta: containerSourceType(), -// ObjectMeta: om(testNS, containerSourceName), -// Spec: sourcesv1alpha1.ContainerSourceSpec{ -// Image: image, -// Args: []string{}, -// Sink: &corev1.ObjectReference{ -// Name: unaddressableName, -// Kind: unaddressableKind, -// APIVersion: unaddressableAPIVersion, -// }, -// }, -// } -// // selflink is not filled in when we create the object, so clear it -// obj.ObjectMeta.SelfLink = "" -// return obj -//} -// -//func getAddressable() *unstructured.Unstructured { -// return &unstructured.Unstructured{ -// Object: map[string]interface{}{ -// "apiVersion": addressableAPIVersion, -// "kind": addressableKind, -// "metadata": map[string]interface{}{ -// "namespace": testNS, -// "name": addressableName, -// }, -// "status": map[string]interface{}{ -// "address": map[string]interface{}{ -// "hostname": addressableDNS, -// }, -// }, -// }, -// } -//} -// -//func getAddressableNoStatus() *unstructured.Unstructured { -// return &unstructured.Unstructured{ -// Object: map[string]interface{}{ -// "apiVersion": unaddressableAPIVersion, -// "kind": unaddressableKind, -// "metadata": map[string]interface{}{ -// "namespace": testNS, -// "name": unaddressableName, -// }, -// }, -// } -//} -// -//func getAddressableNilAddress() *unstructured.Unstructured { -// return &unstructured.Unstructured{ -// Object: map[string]interface{}{ -// "apiVersion": addressableAPIVersion, -// "kind": addressableKind, -// "metadata": map[string]interface{}{ -// "namespace": testNS, -// "name": addressableName, -// }, -// "status": map[string]interface{}{ -// "address": map[string]interface{}(nil), -// }, -// }, -// } -//} -// -func makeDeployment(source *sourcesv1alpha1.ContainerSource) *appsv1.Deployment { +func makeDeployment(source *sourcesv1alpha1.ContainerSource, replicas int32, labels map[string]string, annotations map[string]string) *appsv1.Deployment { args := append(source.Spec.Args, fmt.Sprintf("--sink=%s", sinkURI)) env := append(source.Spec.Env, corev1.EnvVar{Name: "SINK", Value: sinkURI}) + + annos := map[string]string{ + "sidecar.istio.io/inject": "true", + } + for k, v := range annotations { + annos[k] = v + } + + labs := map[string]string{ + "eventing.knative.dev/source": source.Name, + } + for k, v := range labels { + labs[k] = v + } + return &appsv1.Deployment{ - TypeMeta: deploymentType(), + TypeMeta: metav1.TypeMeta{ + APIVersion: appsv1.SchemeGroupVersion.String(), + Kind: "Deployment", + }, ObjectMeta: metav1.ObjectMeta{ GenerateName: fmt.Sprintf("%s-", source.Name), Namespace: source.Namespace, @@ -428,12 +476,8 @@ func makeDeployment(source *sourcesv1alpha1.ContainerSource) *appsv1.Deployment }, Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ - Annotations: map[string]string{ - "sidecar.istio.io/inject": "true", - }, - Labels: map[string]string{ - "eventing.knative.dev/source": source.Name, - }, + Annotations: annos, + Labels: labs, }, Spec: corev1.PodSpec{ Containers: []corev1.Container{{ @@ -447,33 +491,12 @@ func makeDeployment(source *sourcesv1alpha1.ContainerSource) *appsv1.Deployment }, }, }, + Status: appsv1.DeploymentStatus{ + ReadyReplicas: replicas, + }, } } -// -//func containerSourceType() metav1.TypeMeta { -// return metav1.TypeMeta{ -// APIVersion: sourcesv1alpha1.SchemeGroupVersion.String(), -// Kind: "ContainerSource", -// } -//} -// -func deploymentType() metav1.TypeMeta { - return metav1.TypeMeta{ - APIVersion: appsv1.SchemeGroupVersion.String(), - Kind: "Deployment", - } -} - -// -//func om(namespace, name string) metav1.ObjectMeta { -// return metav1.ObjectMeta{ -// Namespace: namespace, -// Name: name, -// SelfLink: fmt.Sprintf("/apis/eventing/sources/v1alpha1/namespaces/%s/object/%s", namespace, name), -// } -//} -// func getOwnerReferences() []metav1.OwnerReference { return []metav1.OwnerReference{{ APIVersion: sourcesv1alpha1.SchemeGroupVersion.String(), diff --git a/pkg/reconciler/containersource/resources/deployment_test.go b/pkg/reconciler/containersource/resources/deployment_test.go index 4351008a2dd..0ac4a82d2fe 100644 --- a/pkg/reconciler/containersource/resources/deployment_test.go +++ b/pkg/reconciler/containersource/resources/deployment_test.go @@ -17,6 +17,7 @@ limitations under the License. package resources import ( + "github.com/knative/eventing/pkg/apis/sources/v1alpha1" "testing" "github.com/google/go-cmp/cmp" @@ -26,7 +27,11 @@ import ( ) func TestMakeDeployment_sinkoverrideannotationlabelnotallowed(t *testing.T) { + yes := true got := MakeDeployment(ContainerArguments{ + Source: &v1alpha1.ContainerSource{ + ObjectMeta: metav1.ObjectMeta{Name: "test-name", UID: "TEST_UID"}, + }, Name: "test-name", Namespace: "test-namespace", Image: "test-image", @@ -63,6 +68,14 @@ func TestMakeDeployment_sinkoverrideannotationlabelnotallowed(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ GenerateName: "test-name-", Namespace: "test-namespace", + OwnerReferences: []metav1.OwnerReference{{ + APIVersion: "sources.eventing.knative.dev/v1alpha1", + Kind: "ContainerSource", + Name: "test-name", + UID: "TEST_UID", + Controller: &yes, + BlockOwnerDeletion: &yes, + }}, }, Spec: appsv1.DeploymentSpec{ Selector: &metav1.LabelSelector{ @@ -121,7 +134,11 @@ func TestMakeDeployment_sinkoverrideannotationlabelnotallowed(t *testing.T) { } func TestMakeDeployment_sink(t *testing.T) { + yes := true got := MakeDeployment(ContainerArguments{ + Source: &v1alpha1.ContainerSource{ + ObjectMeta: metav1.ObjectMeta{Name: "test-name", UID: "TEST_UID"}, + }, Name: "test-name", Namespace: "test-namespace", Image: "test-image", @@ -150,6 +167,14 @@ func TestMakeDeployment_sink(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ GenerateName: "test-name-", Namespace: "test-namespace", + OwnerReferences: []metav1.OwnerReference{{ + APIVersion: "sources.eventing.knative.dev/v1alpha1", + Kind: "ContainerSource", + Name: "test-name", + UID: "TEST_UID", + Controller: &yes, + BlockOwnerDeletion: &yes, + }}, }, Spec: appsv1.DeploymentSpec{ Selector: &metav1.LabelSelector{ @@ -206,7 +231,11 @@ func TestMakeDeployment_sink(t *testing.T) { } func TestMakeDeployment_sinkinargs(t *testing.T) { + yes := true got := MakeDeployment(ContainerArguments{ + Source: &v1alpha1.ContainerSource{ + ObjectMeta: metav1.ObjectMeta{Name: "test-name", UID: "TEST_UID"}, + }, Name: "test-name", Namespace: "test-namespace", Image: "test-image", @@ -236,6 +265,14 @@ func TestMakeDeployment_sinkinargs(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ GenerateName: "test-name-", Namespace: "test-namespace", + OwnerReferences: []metav1.OwnerReference{{ + APIVersion: "sources.eventing.knative.dev/v1alpha1", + Kind: "ContainerSource", + Name: "test-name", + UID: "TEST_UID", + Controller: &yes, + BlockOwnerDeletion: &yes, + }}, }, Spec: appsv1.DeploymentSpec{ Selector: &metav1.LabelSelector{ diff --git a/pkg/reconciler/cronjobsource/cronjobsource_test.go b/pkg/reconciler/cronjobsource/cronjobsource_test.go index a07e6f9c6f8..ce3ed0ca5fd 100644 --- a/pkg/reconciler/cronjobsource/cronjobsource_test.go +++ b/pkg/reconciler/cronjobsource/cronjobsource_test.go @@ -17,46 +17,33 @@ limitations under the License. package cronjobsource import ( - "github.com/knative/eventing/pkg/reconciler/cronjobsource/resources" - "github.com/knative/eventing/pkg/utils" - "k8s.io/apimachinery/pkg/runtime" "os" "testing" + 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" + kubeinformers "k8s.io/client-go/informers" + fakekubeclientset "k8s.io/client-go/kubernetes/fake" + "k8s.io/client-go/kubernetes/scheme" clientgotesting "k8s.io/client-go/testing" + sourcesv1alpha1 "github.com/knative/eventing/pkg/apis/sources/v1alpha1" fakeclientset "github.com/knative/eventing/pkg/client/clientset/versioned/fake" informers "github.com/knative/eventing/pkg/client/informers/externalversions" "github.com/knative/eventing/pkg/reconciler" + "github.com/knative/eventing/pkg/reconciler/cronjobsource/resources" + "github.com/knative/eventing/pkg/utils" duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1" "github.com/knative/pkg/controller" logtesting "github.com/knative/pkg/logging/testing" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - //"k8s.io/apimachinery/pkg/runtime" - kubeinformers "k8s.io/client-go/informers" - fakekubeclientset "k8s.io/client-go/kubernetes/fake" - "k8s.io/client-go/kubernetes/scheme" . "github.com/knative/eventing/pkg/reconciler/testing" . "github.com/knative/pkg/reconciler/testing" - - sourcesv1alpha1 "github.com/knative/eventing/pkg/apis/sources/v1alpha1" - appsv1 "k8s.io/api/apps/v1" ) 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() - - trueVal = true - - sinkGVK = metav1.GroupVersionKind{ - Group: "eventing.knative.dev", - Version: "v1alpha1", - Kind: "Channel", - } sinkRef = corev1.ObjectReference{ Name: sinkName, Kind: "Channel", @@ -69,7 +56,6 @@ var ( const ( image = "github.com/knative/test/image" sourceName = "test-cronjob-source" - sourceUID = "1234-5678-90" testNS = "testnamespace" testSchedule = "*/2 * * * *" testData = "data" diff --git a/pkg/reconciler/testing/containersource.go b/pkg/reconciler/testing/containersource.go index 809832ff869..bc43e909f90 100644 --- a/pkg/reconciler/testing/containersource.go +++ b/pkg/reconciler/testing/containersource.go @@ -17,6 +17,7 @@ limitations under the License. package testing import ( + "k8s.io/apimachinery/pkg/types" "time" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -42,6 +43,12 @@ func NewContainerSource(name, namespace string, o ...ContainerSourceOption) *v1a return c } +func WithContainerSourceUID(uid types.UID) ContainerSourceOption { + return func(s *v1alpha1.ContainerSource) { + s.UID = uid + } +} + // WithInitContainerSourceConditions initializes the ContainerSource's conditions. func WithInitContainerSourceConditions(s *v1alpha1.ContainerSource) { s.Status.InitializeConditions() @@ -71,6 +78,12 @@ func WithContainerSourceDeploying(msg string) ContainerSourceOption { } } +func WithContainerSourceDeployFailed(msg string) ContainerSourceOption { + return func(s *v1alpha1.ContainerSource) { + s.Status.MarkNotDeployed("DeploymentCreateFailed", msg) + } +} + func WithContainerSourceDeployed(s *v1alpha1.ContainerSource) { s.Status.MarkDeployed() } @@ -85,3 +98,15 @@ func WithContainerSourceSpec(spec v1alpha1.ContainerSourceSpec) ContainerSourceO c.Spec = spec } } + +func WithContainerSourceLabels(labels map[string]string) ContainerSourceOption { + return func(c *v1alpha1.ContainerSource) { + c.Labels = labels + } +} + +func WithContainerSourceAnnotations(annotations map[string]string) ContainerSourceOption { + return func(c *v1alpha1.ContainerSource) { + c.Annotations = annotations + } +} From 9f729e311d5bed6314a47abafc121e4dd0139e45 Mon Sep 17 00:00:00 2001 From: Scott Nichols Date: Thu, 25 Apr 2019 13:26:29 -0700 Subject: [PATCH 25/25] rbac. --- config/200-controller-clusterrole.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/config/200-controller-clusterrole.yaml b/config/200-controller-clusterrole.yaml index 44a8d3f1408..5be03648e78 100644 --- a/config/200-controller-clusterrole.yaml +++ b/config/200-controller-clusterrole.yaml @@ -79,4 +79,7 @@ rules: - "cronjobsources" - "cronjobsources/status" - "cronjobsources/finalizers" + - "containersources" + - "containersources/status" + - "containersources/finalizers" verbs: *everything