From f7452f45e9dad568ce27822df0c6589313a43bd0 Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Mon, 23 Mar 2020 17:04:26 -0700 Subject: [PATCH 01/16] adding ContainerSource back --- cmd/controller/main.go | 2 + cmd/webhook/main.go | 1 + config/300-containersource.yaml | 1 + config/core/resources/containersource.yaml | 62 +++ .../roles/source-observer-clusterrole.yaml | 3 +- .../sources-controller-clusterroles.yaml | 3 + pkg/apis/sources/register.go | 6 + .../sources/v1alpha1/container_defaults.go | 42 ++ .../v1alpha1/container_defaults_test.go | 115 +++++ .../sources/v1alpha1/container_lifecycle.go | 86 ++++ .../v1alpha1/container_lifecycle_test.go | 324 ++++++++++++++ pkg/apis/sources/v1alpha1/container_types.go | 92 ++++ .../sources/v1alpha1/container_validation.go | 59 +++ .../v1alpha1/container_validation_test.go | 112 +++++ pkg/apis/sources/v1alpha1/implements_test.go | 4 +- pkg/apis/sources/v1alpha1/register.go | 2 + .../sources/v1alpha1/zz_generated.deepcopy.go | 96 ++++ .../typed/sources/v1alpha1/containersource.go | 191 ++++++++ .../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 + .../containersource/containersource.go | 52 +++ .../v1alpha1/containersource/fake/fake.go | 40 ++ .../v1alpha1/containersource/controller.go | 97 ++++ .../v1alpha1/containersource/reconciler.go | 323 ++++++++++++++ .../containersource/stub/controller.go | 54 +++ .../containersource/stub/reconciler.go | 64 +++ .../sources/v1alpha1/containersource.go | 94 ++++ .../sources/v1alpha1/expansion_generated.go | 8 + .../containersource/containersource.go | 168 +++++++ .../containersource/containersource_test.go | 420 ++++++++++++++++++ pkg/reconciler/containersource/controller.go | 71 +++ .../containersource/controller_test.go | 41 ++ .../containersource/resources/deployment.go | 80 ++++ .../resources/deployment_test.go | 330 ++++++++++++++ .../containersource/resources/labels.go | 28 ++ pkg/reconciler/testing/containersource.go | 123 +++++ pkg/reconciler/testing/listers.go | 4 + test/e2e/source_container_test.go | 100 +++++ test/lib/creation.go | 11 + 44 files changed, 3556 insertions(+), 2 deletions(-) create mode 120000 config/300-containersource.yaml create mode 100644 config/core/resources/containersource.yaml create mode 100644 pkg/apis/sources/v1alpha1/container_defaults.go create mode 100644 pkg/apis/sources/v1alpha1/container_defaults_test.go create mode 100644 pkg/apis/sources/v1alpha1/container_lifecycle.go create mode 100644 pkg/apis/sources/v1alpha1/container_lifecycle_test.go create mode 100644 pkg/apis/sources/v1alpha1/container_types.go create mode 100644 pkg/apis/sources/v1alpha1/container_validation.go create mode 100644 pkg/apis/sources/v1alpha1/container_validation_test.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/injection/informers/sources/v1alpha1/containersource/containersource.go create mode 100644 pkg/client/injection/informers/sources/v1alpha1/containersource/fake/fake.go create mode 100644 pkg/client/injection/reconciler/sources/v1alpha1/containersource/controller.go create mode 100644 pkg/client/injection/reconciler/sources/v1alpha1/containersource/reconciler.go create mode 100644 pkg/client/injection/reconciler/sources/v1alpha1/containersource/stub/controller.go create mode 100644 pkg/client/injection/reconciler/sources/v1alpha1/containersource/stub/reconciler.go create mode 100644 pkg/client/listers/sources/v1alpha1/containersource.go create mode 100644 pkg/reconciler/containersource/containersource.go create mode 100644 pkg/reconciler/containersource/containersource_test.go create mode 100644 pkg/reconciler/containersource/controller.go create mode 100644 pkg/reconciler/containersource/controller_test.go create mode 100644 pkg/reconciler/containersource/resources/deployment.go create mode 100644 pkg/reconciler/containersource/resources/deployment_test.go create mode 100644 pkg/reconciler/containersource/resources/labels.go create mode 100644 pkg/reconciler/testing/containersource.go create mode 100644 test/e2e/source_container_test.go diff --git a/cmd/controller/main.go b/cmd/controller/main.go index b11bcd72b6f..cf3848f8a55 100644 --- a/cmd/controller/main.go +++ b/cmd/controller/main.go @@ -24,6 +24,7 @@ import ( "knative.dev/eventing/pkg/reconciler/apiserversource" "knative.dev/eventing/pkg/reconciler/channel" + "knative.dev/eventing/pkg/reconciler/containersource" "knative.dev/eventing/pkg/reconciler/eventtype" "knative.dev/eventing/pkg/reconciler/parallel" pingsource "knative.dev/eventing/pkg/reconciler/pingsource/controller" @@ -51,6 +52,7 @@ func main() { // Sources apiserversource.NewController, pingsource.NewController, + containersource.NewController, // Sources CRD sourcecrd.NewController, ) diff --git a/cmd/webhook/main.go b/cmd/webhook/main.go index d3221ed0be2..ec062d01db8 100644 --- a/cmd/webhook/main.go +++ b/cmd/webhook/main.go @@ -86,6 +86,7 @@ var ourTypes = map[schema.GroupVersionKind]resourcesemantics.GenericCRD{ sourcesv1alpha1.SchemeGroupVersion.WithKind("ApiServerSource"): &sourcesv1alpha1.ApiServerSource{}, sourcesv1alpha1.SchemeGroupVersion.WithKind("PingSource"): &sourcesv1alpha1.PingSource{}, sourcesv1alpha1.SchemeGroupVersion.WithKind("SinkBinding"): &sourcesv1alpha1.SinkBinding{}, + sourcesv1alpha1.SchemeGroupVersion.WithKind("ContainerSource"): &sourcesv1alpha1.ContainerSource{}, // v1alpha2 sourcesv1alpha2.SchemeGroupVersion.WithKind("ApiServerSource"): &sourcesv1alpha2.ApiServerSource{}, sourcesv1alpha2.SchemeGroupVersion.WithKind("PingSource"): &sourcesv1alpha2.PingSource{}, diff --git a/config/300-containersource.yaml b/config/300-containersource.yaml new file mode 120000 index 00000000000..3ffe43ecf6c --- /dev/null +++ b/config/300-containersource.yaml @@ -0,0 +1 @@ +core/resources/containersource.yaml \ No newline at end of file diff --git a/config/core/resources/containersource.yaml b/config/core/resources/containersource.yaml new file mode 100644 index 00000000000..2602817a3dc --- /dev/null +++ b/config/core/resources/containersource.yaml @@ -0,0 +1,62 @@ +# Copyright 2020 The Knative Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + labels: + eventing.knative.dev/release: devel + eventing.knative.dev/source: "true" + duck.knative.dev/source: "true" + knative.dev/crd-install: "true" + name: containersources.sources.knative.dev +spec: + group: sources.knative.dev + names: + categories: + - all + - knative + - eventing + - sources + kind: ContainerSource + plural: containersources + scope: Namespaced + subresources: + status: {} + preserveUnknownFields: false + validation: + openAPIV3Schema: + type: object + # this is a work around so we don't need to flesh out the + # schema for each version at this time + # + # see issue: https://github.com/knative/serving/issues/912 + x-kubernetes-preserve-unknown-fields: true + additionalPrinterColumns: + - name: Ready + type: string + JSONPath: ".status.conditions[?(@.type==\"Ready\")].status" + - name: Reason + type: string + JSONPath: ".status.conditions[?(@.type=='Ready')].reason" + - name: Sink + type: string + JSONPath: ".status.sinkUri" + - name: Age + type: date + JSONPath: .metadata.creationTimestamp + versions: + - name: v1alpha1 + served: true + storage: true diff --git a/config/core/roles/source-observer-clusterrole.yaml b/config/core/roles/source-observer-clusterrole.yaml index 6f54856054b..c53bcd93253 100644 --- a/config/core/roles/source-observer-clusterrole.yaml +++ b/config/core/roles/source-observer-clusterrole.yaml @@ -41,7 +41,8 @@ rules: resources: - apiserversources - pingsources - - sinkbinding + - sinkbindings + - containersources verbs: - get - list diff --git a/config/core/roles/sources-controller-clusterroles.yaml b/config/core/roles/sources-controller-clusterroles.yaml index bdf0bbca582..688cbd03f7d 100644 --- a/config/core/roles/sources-controller-clusterroles.yaml +++ b/config/core/roles/sources-controller-clusterroles.yaml @@ -54,6 +54,9 @@ rules: - "pingsources" - "pingsources/status" - "pingsources/finalizers" + - "containersources" + - "containersources/status" + - "containersources/finalizers" verbs: *everything # Knative Services admin diff --git a/pkg/apis/sources/register.go b/pkg/apis/sources/register.go index 55899c3fd77..d627779cfd9 100644 --- a/pkg/apis/sources/register.go +++ b/pkg/apis/sources/register.go @@ -50,4 +50,10 @@ var ( Group: GroupName, Resource: "sinkbindings", } + + // ContainerSourceResource respresents a Knative Eventing Sources ContainerSource + ContainerSourceResource = schema.GroupResource{ + Group: GroupName, + Resource: "containersources", + } ) diff --git a/pkg/apis/sources/v1alpha1/container_defaults.go b/pkg/apis/sources/v1alpha1/container_defaults.go new file mode 100644 index 00000000000..ee52e33b4b5 --- /dev/null +++ b/pkg/apis/sources/v1alpha1/container_defaults.go @@ -0,0 +1,42 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + "context" + "fmt" + + corev1 "k8s.io/api/core/v1" + "knative.dev/pkg/apis" +) + +func (s *ContainerSource) SetDefaults(ctx context.Context) { + withName := apis.WithinParent(ctx, s.ObjectMeta) + s.Spec.SetDefaults(withName) +} + +func (ss *ContainerSourceSpec) SetDefaults(ctx context.Context) { + containers := make([]corev1.Container, 0, len(ss.Template.Spec.Containers)) + for i, c := range ss.Template.Spec.Containers { + // If the Container specified has no name, then default to "_". + if c.Name == "" { + c.Name = fmt.Sprintf("%s-%d", apis.ParentMeta(ctx).Name, i) + } + containers = append(containers, c) + } + ss.Template.Spec.Containers = containers +} diff --git a/pkg/apis/sources/v1alpha1/container_defaults_test.go b/pkg/apis/sources/v1alpha1/container_defaults_test.go new file mode 100644 index 00000000000..701080b0423 --- /dev/null +++ b/pkg/apis/sources/v1alpha1/container_defaults_test.go @@ -0,0 +1,115 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + "context" + "testing" + + "github.com/google/go-cmp/cmp" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// No-op test because method does nothing. +func TestContainerSourceDefaults(t *testing.T) { + testCases := map[string]struct { + initial ContainerSource + expected ContainerSource + }{ + "no container name": { + initial: ContainerSource{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-name", + Namespace: "test-namespace", + }, + Spec: ContainerSourceSpec{ + Template: corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + Containers: []corev1.Container{{ + Image: "test-image", + }}, + }, + }, + }, + }, + expected: ContainerSource{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-name", + Namespace: "test-namespace", + }, + Spec: ContainerSourceSpec{ + Template: corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + Containers: []corev1.Container{{ + Name: "test-name-0", + Image: "test-image", + }}, + }, + }, + }, + }, + }, + "one with ontainer name one without": { + initial: ContainerSource{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-name", + Namespace: "test-namespace", + }, + Spec: ContainerSourceSpec{ + Template: corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + Containers: []corev1.Container{{ + Name: "test-container", + Image: "test-image", + }, { + Image: "test-another-image", + }}, + }, + }, + }, + }, + expected: ContainerSource{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-name", + Namespace: "test-namespace", + }, + Spec: ContainerSourceSpec{ + Template: corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + Containers: []corev1.Container{{ + Name: "test-container", + Image: "test-image", + }, { + Name: "test-name-1", + Image: "test-another-image", + }}, + }, + }, + }, + }, + }, + } + for n, tc := range testCases { + t.Run(n, func(t *testing.T) { + tc.initial.SetDefaults(context.Background()) + if diff := cmp.Diff(tc.expected, tc.initial); diff != "" { + t.Fatalf("Unexpected defaults (-want, +got): %s", diff) + } + }) + } +} diff --git a/pkg/apis/sources/v1alpha1/container_lifecycle.go b/pkg/apis/sources/v1alpha1/container_lifecycle.go new file mode 100644 index 00000000000..550911e8adc --- /dev/null +++ b/pkg/apis/sources/v1alpha1/container_lifecycle.go @@ -0,0 +1,86 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + appsv1 "k8s.io/api/apps/v1" + "knative.dev/eventing/pkg/apis/duck" + "knative.dev/pkg/apis" +) + +const ( + // ContainerSourceConditionReady has status True when the ContainerSource is ready to send events. + ContainerConditionReady = apis.ConditionReady + + // ContainerConditionSinkProvided has status True when the ContainerSource has been configured with a sink target. + ContainerConditionSinkProvided apis.ConditionType = "SinkProvided" + + // ContainerConditionDeployed has status True when the ContainerSource has had it's deployment created. + ContainerConditionDeployed apis.ConditionType = "Deployed" +) + +var containerCondSet = apis.NewLivingConditionSet( + ContainerConditionSinkProvided, + ContainerConditionDeployed, +) + +// GetCondition returns the condition currently associated with the given type, or nil. +func (s *ContainerSourceStatus) GetCondition(t apis.ConditionType) *apis.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 *apis.URL) { + s.SinkURI = uri + if !uri.IsEmpty() { + containerCondSet.Manage(s).MarkTrue(ContainerConditionSinkProvided) + } else { + containerCondSet.Manage(s).MarkFalse(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...) +} + +// PropagateDeploymentAvailability uses the availability of the provided Deployment to determine if +// ContainerConditionDeployed should be marked as true or false. +func (s *ContainerSourceStatus) PropagateDeploymentAvailability(d *appsv1.Deployment) { + if duck.DeploymentIsAvailable(&d.Status, false) { + containerCondSet.Manage(s).MarkTrue(ContainerConditionDeployed) + } else { + // I don't know how to propagate the status well, so just give the name of the Deployment + // for now. + containerCondSet.Manage(s).MarkFalse(ContainerConditionDeployed, "DeploymentUnavailable", "The Deployment '%s' is unavailable.", d.Name) + } +} + +// 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/container_lifecycle_test.go b/pkg/apis/sources/v1alpha1/container_lifecycle_test.go new file mode 100644 index 00000000000..4c21c250eb5 --- /dev/null +++ b/pkg/apis/sources/v1alpha1/container_lifecycle_test.go @@ -0,0 +1,324 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + "testing" + + "github.com/google/go-cmp/cmp/cmpopts" + + "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" + "knative.dev/pkg/apis" +) + +var ( + availDeployment = &appsv1.Deployment{ + Status: appsv1.DeploymentStatus{ + Conditions: []appsv1.DeploymentCondition{ + { + Type: appsv1.DeploymentAvailable, + Status: corev1.ConditionTrue, + }, + }, + }, + } + unavailDeployment = &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-name", + Namespace: "test-namespace", + }, + Status: appsv1.DeploymentStatus{ + Conditions: []appsv1.DeploymentCondition{ + { + Type: appsv1.DeploymentAvailable, + Status: corev1.ConditionFalse, + }, + }, + }, + } +) + +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.PropagateDeploymentAvailability(availDeployment) + return s + }(), + want: false, + }, { + name: "mark sink", + s: func() *ContainerSourceStatus { + s := &ContainerSourceStatus{} + s.InitializeConditions() + s.MarkSink(apis.HTTP("example")) + return s + }(), + want: false, + }, { + name: "mark sink and deployed", + s: func() *ContainerSourceStatus { + s := &ContainerSourceStatus{} + s.InitializeConditions() + s.MarkSink(apis.HTTP("example")) + s.PropagateDeploymentAvailability(availDeployment) + return s + }(), + want: true, + }, { + name: "mark sink and deployed then no sink", + s: func() *ContainerSourceStatus { + s := &ContainerSourceStatus{} + s.InitializeConditions() + s.MarkSink(apis.HTTP("example")) + s.PropagateDeploymentAvailability(availDeployment) + s.MarkNoSink("Testing", "") + return s + }(), + want: false, + }, { + name: "mark sink and deployed then not deployed", + s: func() *ContainerSourceStatus { + s := &ContainerSourceStatus{} + s.InitializeConditions() + s.MarkSink(apis.HTTP("example")) + s.PropagateDeploymentAvailability(availDeployment) + s.PropagateDeploymentAvailability(unavailDeployment) + return s + }(), + want: false, + }, { + name: "mark sink nil and deployed", + s: func() *ContainerSourceStatus { + s := &ContainerSourceStatus{} + s.InitializeConditions() + s.MarkSink(nil) + s.PropagateDeploymentAvailability(availDeployment) + return s + }(), + want: false, + }, { + name: "mark sink empty and deployed", + s: func() *ContainerSourceStatus { + s := &ContainerSourceStatus{} + s.InitializeConditions() + s.MarkSink(&apis.URL{}) + s.PropagateDeploymentAvailability(availDeployment) + return s + }(), + want: false, + }, { + name: "mark sink nil and deployed then sink", + s: func() *ContainerSourceStatus { + s := &ContainerSourceStatus{} + s.InitializeConditions() + s.MarkSink(nil) + s.PropagateDeploymentAvailability(availDeployment) + s.MarkSink(apis.HTTP("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 apis.ConditionType + want *apis.Condition + }{{ + name: "uninitialized", + s: &ContainerSourceStatus{}, + condQuery: ContainerConditionReady, + want: nil, + }, { + name: "initialized", + s: func() *ContainerSourceStatus { + s := &ContainerSourceStatus{} + s.InitializeConditions() + return s + }(), + condQuery: ContainerConditionReady, + want: &apis.Condition{ + Type: ContainerConditionReady, + Status: corev1.ConditionUnknown, + }, + }, { + name: "mark deployed", + s: func() *ContainerSourceStatus { + s := &ContainerSourceStatus{} + s.InitializeConditions() + s.PropagateDeploymentAvailability(availDeployment) + return s + }(), + condQuery: ContainerConditionReady, + want: &apis.Condition{ + Type: ContainerConditionReady, + Status: corev1.ConditionUnknown, + }, + }, { + name: "mark sink", + s: func() *ContainerSourceStatus { + s := &ContainerSourceStatus{} + s.InitializeConditions() + s.MarkSink(apis.HTTP("example")) + return s + }(), + condQuery: ContainerConditionReady, + want: &apis.Condition{ + Type: ContainerConditionReady, + Status: corev1.ConditionUnknown, + }, + }, { + name: "mark sink and deployed", + s: func() *ContainerSourceStatus { + s := &ContainerSourceStatus{} + s.InitializeConditions() + s.MarkSink(apis.HTTP("example")) + s.PropagateDeploymentAvailability(availDeployment) + return s + }(), + condQuery: ContainerConditionReady, + want: &apis.Condition{ + Type: ContainerConditionReady, + Status: corev1.ConditionTrue, + }, + }, { + name: "mark sink and deployed then no sink", + s: func() *ContainerSourceStatus { + s := &ContainerSourceStatus{} + s.InitializeConditions() + s.MarkSink(apis.HTTP("example")) + s.PropagateDeploymentAvailability(availDeployment) + s.MarkNoSink("Testing", "hi%s", "") + return s + }(), + condQuery: ContainerConditionReady, + want: &apis.Condition{ + Type: ContainerConditionReady, + Status: corev1.ConditionFalse, + Reason: "Testing", + Message: "hi", + }, + }, { + name: "mark sink and deployed then not deployed", + s: func() *ContainerSourceStatus { + s := &ContainerSourceStatus{} + s.InitializeConditions() + s.MarkSink(apis.HTTP("example")) + s.PropagateDeploymentAvailability(availDeployment) + s.PropagateDeploymentAvailability(unavailDeployment) + return s + }(), + condQuery: ContainerConditionReady, + want: &apis.Condition{ + Type: ContainerConditionReady, + Status: corev1.ConditionFalse, + Reason: "DeploymentUnavailable", + Message: "The Deployment 'test-name' is unavailable.", + }, + }, { + name: "mark sink nil and deployed", + s: func() *ContainerSourceStatus { + s := &ContainerSourceStatus{} + s.InitializeConditions() + s.MarkSink(nil) + s.PropagateDeploymentAvailability(availDeployment) + return s + }(), + condQuery: ContainerConditionReady, + want: &apis.Condition{ + Type: ContainerConditionReady, + Status: corev1.ConditionFalse, + Reason: "SinkEmpty", + Message: "Sink has resolved to empty.", + }, + }, { + name: "mark sink empty and deployed", + s: func() *ContainerSourceStatus { + s := &ContainerSourceStatus{} + s.InitializeConditions() + s.MarkSink(&apis.URL{}) + s.PropagateDeploymentAvailability(availDeployment) + return s + }(), + condQuery: ContainerConditionReady, + want: &apis.Condition{ + Type: ContainerConditionReady, + Status: corev1.ConditionFalse, + Reason: "SinkEmpty", + Message: "Sink has resolved to empty.", + }, + }, { + name: "mark sink nil and deployed then sink", + s: func() *ContainerSourceStatus { + s := &ContainerSourceStatus{} + s.InitializeConditions() + s.MarkSink(nil) + s.PropagateDeploymentAvailability(availDeployment) + s.MarkSink(apis.HTTP("example")) + return s + }(), + condQuery: ContainerConditionReady, + want: &apis.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(apis.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/container_types.go b/pkg/apis/sources/v1alpha1/container_types.go new file mode 100644 index 00000000000..66e96856ec7 --- /dev/null +++ b/pkg/apis/sources/v1alpha1/container_types.go @@ -0,0 +1,92 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +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" + "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" + "knative.dev/pkg/kmeta" +) + +// +genclient +// +genreconciler +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// 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"` +} + +var ( + _ runtime.Object = (*ContainerSource)(nil) + _ kmeta.OwnerRefable = (*ContainerSource)(nil) + _ apis.Validatable = (*ContainerSource)(nil) + _ apis.Defaultable = (*ContainerSource)(nil) + _ apis.HasSpec = (*ContainerSource)(nil) +) + +// ContainerSourceSpec defines the desired state of ContainerSource +type ContainerSourceSpec struct { + // inherits duck/v1 SourceSpec, which currently provides: + // * Sink - a reference to an object that will resolve to a domain name or + // a URI directly to use as the sink. + // * CloudEventOverrides - defines overrides to control the output format + // and modifications of the event sent to the sink. + duckv1.SourceSpec `json:",inline"` + + // Template describes the pods that will be created + Template corev1.PodTemplateSpec `json:"template,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/v1 SourceStatus, 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. + // * SinkURI - the current active sink URI that has been configured for the + // Source. + duckv1.SourceStatus `json:",inline"` +} + +// +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"` +} + +// GetUntypedSpec returns the spec of the ContainerSource. +func (c *ContainerSource) GetUntypedSpec() interface{} { + return c.Spec +} diff --git a/pkg/apis/sources/v1alpha1/container_validation.go b/pkg/apis/sources/v1alpha1/container_validation.go new file mode 100644 index 00000000000..cd1960cdde3 --- /dev/null +++ b/pkg/apis/sources/v1alpha1/container_validation.go @@ -0,0 +1,59 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + "context" + + corev1 "k8s.io/api/core/v1" + "knative.dev/pkg/apis" +) + +func (c *ContainerSource) Validate(ctx context.Context) *apis.FieldError { + return c.Spec.Validate(ctx).ViaField("spec") +} + +func (cs *ContainerSourceSpec) Validate(ctx context.Context) *apis.FieldError { + var errs *apis.FieldError + if fe := cs.Sink.Validate(ctx); fe != nil { + errs = errs.Also(fe.ViaField("sink")) + } + + // Validate there is at least a container + if cs.Template.Spec.Containers == nil || len(cs.Template.Spec.Containers) == 0 { + fe := apis.ErrMissingField("containers") + errs = errs.Also(fe) + } else { + for i, c := range cs.Template.Spec.Containers { + if ce := isValidContainer(&c); ce != nil { + errs = errs.Also(ce.ViaFieldIndex("containers", i)) + } + } + } + return errs +} + +func isValidContainer(c *corev1.Container) *apis.FieldError { + var errs *apis.FieldError + if c.Name == "" { + errs = errs.Also(apis.ErrMissingField("name")) + } + if c.Image == "" { + errs = errs.Also(apis.ErrMissingField("image")) + } + return errs +} diff --git a/pkg/apis/sources/v1alpha1/container_validation_test.go b/pkg/apis/sources/v1alpha1/container_validation_test.go new file mode 100644 index 00000000000..e64df8eca28 --- /dev/null +++ b/pkg/apis/sources/v1alpha1/container_validation_test.go @@ -0,0 +1,112 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + "context" + "testing" + + "github.com/google/go-cmp/cmp" + corev1 "k8s.io/api/core/v1" + "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" +) + +func TestContainerSourceValidation(t *testing.T) { + tests := []struct { + name string + spec ContainerSourceSpec + want *apis.FieldError + }{{ + name: "missing container", + spec: ContainerSourceSpec{ + Template: corev1.PodTemplateSpec{}, + SourceSpec: duckv1.SourceSpec{ + Sink: duckv1.Destination{ + Ref: &duckv1.KReference{ + APIVersion: "v1alpha1", + Kind: "Broker", + Name: "default", + }, + }, + }, + }, + want: func() *apis.FieldError { + var errs *apis.FieldError + fe := apis.ErrMissingField("containers") + errs = errs.Also(fe) + return errs + }(), + }, { + name: "missing container image", + spec: ContainerSourceSpec{ + Template: corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + Containers: []corev1.Container{{ + Name: "test-name", + }}, + }, + }, + SourceSpec: duckv1.SourceSpec{ + Sink: duckv1.Destination{ + Ref: &duckv1.KReference{ + APIVersion: "eventing.knative.dev/v1alpha1", + Kind: "Broker", + Name: "default", + }, + }, + }, + }, + want: func() *apis.FieldError { + var errs *apis.FieldError + fe := apis.ErrMissingField("containers[0].image") + errs = errs.Also(fe) + return errs + }(), + }, { + name: "empty sink", + spec: ContainerSourceSpec{ + Template: corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + Containers: []corev1.Container{{ + Name: "name", + Image: "image", + }}, + }, + }, + SourceSpec: duckv1.SourceSpec{ + Sink: duckv1.Destination{}, + }, + }, + want: func() *apis.FieldError { + var errs *apis.FieldError + fe := apis.ErrGeneric("expected at least one, got none", "sink.ref", "sink.uri") + errs = errs.Also(fe) + return errs + }(), + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := test.spec.Validate(context.TODO()) + if diff := cmp.Diff(test.want.Error(), got.Error()); diff != "" { + t.Errorf("ContainerSourceSpec.Validate (-want, +got) = %v", diff) + } + }) + } +} diff --git a/pkg/apis/sources/v1alpha1/implements_test.go b/pkg/apis/sources/v1alpha1/implements_test.go index 9c43f176cb8..a7e3dd8c9ff 100644 --- a/pkg/apis/sources/v1alpha1/implements_test.go +++ b/pkg/apis/sources/v1alpha1/implements_test.go @@ -27,9 +27,11 @@ func TestTypesImplements(t *testing.T) { iface duck.Implementable }{ // PingSource + {instance: &PingSource{}, iface: &duckv1.Conditions{}}, + // ApiServerSource {instance: &ApiServerSource{}, iface: &duckv1.Conditions{}}, // ContainerSource - {instance: &ApiServerSource{}, iface: &duckv1.Conditions{}}, + {instance: &ContainerSource{}, iface: &duckv1.Conditions{}}, // SinkBinding {instance: &SinkBinding{}, iface: &duckv1.Conditions{}}, {instance: &SinkBinding{}, iface: &duckv1beta1.Source{}}, diff --git a/pkg/apis/sources/v1alpha1/register.go b/pkg/apis/sources/v1alpha1/register.go index 23aafaf34d2..9809733a80f 100644 --- a/pkg/apis/sources/v1alpha1/register.go +++ b/pkg/apis/sources/v1alpha1/register.go @@ -51,6 +51,8 @@ func addKnownTypes(scheme *runtime.Scheme) error { &PingSourceList{}, &SinkBinding{}, &SinkBindingList{}, + &ContainerSource{}, + &ContainerSourceList{}, ) metav1.AddToGroupVersion(scheme, SchemeGroupVersion) return nil diff --git a/pkg/apis/sources/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/sources/v1alpha1/zz_generated.deepcopy.go index 40338335045..3eaf09efa9c 100644 --- a/pkg/apis/sources/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/sources/v1alpha1/zz_generated.deepcopy.go @@ -167,6 +167,102 @@ func (in *ApiServerSourceStatus) DeepCopy() *ApiServerSourceStatus { 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 + in.ListMeta.DeepCopyInto(&out.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 + in.SourceSpec.DeepCopyInto(&out.SourceSpec) + in.Template.DeepCopyInto(&out.Template) + 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.SourceStatus.DeepCopyInto(&out.SourceStatus) + 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 *PingLimitsSpec) DeepCopyInto(out *PingLimitsSpec) { *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..b26c50137a9 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/sources/v1alpha1/containersource.go @@ -0,0 +1,191 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "time" + + 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" + v1alpha1 "knative.dev/eventing/pkg/apis/sources/v1alpha1" + scheme "knative.dev/eventing/pkg/client/clientset/versioned/scheme" +) + +// 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) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1alpha1.ContainerSourceList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("containersources"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested containerSources. +func (c *containerSources) Watch(opts v1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("containersources"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + 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 { + var timeout time.Duration + if listOptions.TimeoutSeconds != nil { + timeout = time.Duration(*listOptions.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Namespace(c.ns). + Resource("containersources"). + VersionedParams(&listOptions, scheme.ParameterCodec). + Timeout(timeout). + 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..c7701ae9430 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/sources/v1alpha1/fake/fake_containersource.go @@ -0,0 +1,140 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + v1alpha1 "knative.dev/eventing/pkg/apis/sources/v1alpha1" +) + +// FakeContainerSources implements ContainerSourceInterface +type FakeContainerSources struct { + Fake *FakeSourcesV1alpha1 + ns string +} + +var containersourcesResource = schema.GroupVersionResource{Group: "sources.knative.dev", Version: "v1alpha1", Resource: "containersources"} + +var containersourcesKind = schema.GroupVersionKind{Group: "sources.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, pt, 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 59cd493e70b..d1be82fdf97 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 @@ -32,6 +32,10 @@ func (c *FakeSourcesV1alpha1) ApiServerSources(namespace string) v1alpha1.ApiSer return &FakeApiServerSources{c, namespace} } +func (c *FakeSourcesV1alpha1) ContainerSources(namespace string) v1alpha1.ContainerSourceInterface { + return &FakeContainerSources{c, namespace} +} + func (c *FakeSourcesV1alpha1) PingSources(namespace string) v1alpha1.PingSourceInterface { return &FakePingSources{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 aa618931ea9..f8047e557db 100644 --- a/pkg/client/clientset/versioned/typed/sources/v1alpha1/generated_expansion.go +++ b/pkg/client/clientset/versioned/typed/sources/v1alpha1/generated_expansion.go @@ -20,6 +20,8 @@ package v1alpha1 type ApiServerSourceExpansion interface{} +type ContainerSourceExpansion interface{} + type PingSourceExpansion interface{} type SinkBindingExpansion 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 08031fe8049..f505eb3e6ae 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 ApiServerSourcesGetter + ContainerSourcesGetter PingSourcesGetter SinkBindingsGetter } @@ -40,6 +41,10 @@ func (c *SourcesV1alpha1Client) ApiServerSources(namespace string) ApiServerSour return newApiServerSources(c, namespace) } +func (c *SourcesV1alpha1Client) ContainerSources(namespace string) ContainerSourceInterface { + return newContainerSources(c, namespace) +} + func (c *SourcesV1alpha1Client) PingSources(namespace string) PingSourceInterface { return newPingSources(c, namespace) } diff --git a/pkg/client/informers/externalversions/generic.go b/pkg/client/informers/externalversions/generic.go index 67f03eec65f..fb59e139586 100644 --- a/pkg/client/informers/externalversions/generic.go +++ b/pkg/client/informers/externalversions/generic.go @@ -111,6 +111,8 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource // Group=sources.knative.dev, Version=v1alpha1 case sourcesv1alpha1.SchemeGroupVersion.WithResource("apiserversources"): return &genericInformer{resource: resource.GroupResource(), informer: f.Sources().V1alpha1().ApiServerSources().Informer()}, nil + case sourcesv1alpha1.SchemeGroupVersion.WithResource("containersources"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Sources().V1alpha1().ContainerSources().Informer()}, nil case sourcesv1alpha1.SchemeGroupVersion.WithResource("pingsources"): return &genericInformer{resource: resource.GroupResource(), informer: f.Sources().V1alpha1().PingSources().Informer()}, nil case sourcesv1alpha1.SchemeGroupVersion.WithResource("sinkbindings"): 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..79660d1a416 --- /dev/null +++ b/pkg/client/informers/externalversions/sources/v1alpha1/containersource.go @@ -0,0 +1,89 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + time "time" + + 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" + sourcesv1alpha1 "knative.dev/eventing/pkg/apis/sources/v1alpha1" + versioned "knative.dev/eventing/pkg/client/clientset/versioned" + internalinterfaces "knative.dev/eventing/pkg/client/informers/externalversions/internalinterfaces" + v1alpha1 "knative.dev/eventing/pkg/client/listers/sources/v1alpha1" +) + +// 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 9ddc57ca546..f8d4a5d4e2a 100644 --- a/pkg/client/informers/externalversions/sources/v1alpha1/interface.go +++ b/pkg/client/informers/externalversions/sources/v1alpha1/interface.go @@ -26,6 +26,8 @@ import ( type Interface interface { // ApiServerSources returns a ApiServerSourceInformer. ApiServerSources() ApiServerSourceInformer + // ContainerSources returns a ContainerSourceInformer. + ContainerSources() ContainerSourceInformer // PingSources returns a PingSourceInformer. PingSources() PingSourceInformer // SinkBindings returns a SinkBindingInformer. @@ -48,6 +50,11 @@ func (v *version) ApiServerSources() ApiServerSourceInformer { return &apiServerSourceInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} } +// ContainerSources returns a ContainerSourceInformer. +func (v *version) ContainerSources() ContainerSourceInformer { + return &containerSourceInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} + // PingSources returns a PingSourceInformer. func (v *version) PingSources() PingSourceInformer { return &pingSourceInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} diff --git a/pkg/client/injection/informers/sources/v1alpha1/containersource/containersource.go b/pkg/client/injection/informers/sources/v1alpha1/containersource/containersource.go new file mode 100644 index 00000000000..11b5cc737a7 --- /dev/null +++ b/pkg/client/injection/informers/sources/v1alpha1/containersource/containersource.go @@ -0,0 +1,52 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package containersource + +import ( + context "context" + + v1alpha1 "knative.dev/eventing/pkg/client/informers/externalversions/sources/v1alpha1" + factory "knative.dev/eventing/pkg/client/injection/informers/factory" + controller "knative.dev/pkg/controller" + injection "knative.dev/pkg/injection" + logging "knative.dev/pkg/logging" +) + +func init() { + injection.Default.RegisterInformer(withInformer) +} + +// Key is used for associating the Informer inside the context.Context. +type Key struct{} + +func withInformer(ctx context.Context) (context.Context, controller.Informer) { + f := factory.Get(ctx) + inf := f.Sources().V1alpha1().ContainerSources() + return context.WithValue(ctx, Key{}, inf), inf.Informer() +} + +// Get extracts the typed informer from the context. +func Get(ctx context.Context) v1alpha1.ContainerSourceInformer { + untyped := ctx.Value(Key{}) + if untyped == nil { + logging.FromContext(ctx).Panic( + "Unable to fetch knative.dev/eventing/pkg/client/informers/externalversions/sources/v1alpha1.ContainerSourceInformer from context.") + } + return untyped.(v1alpha1.ContainerSourceInformer) +} diff --git a/pkg/client/injection/informers/sources/v1alpha1/containersource/fake/fake.go b/pkg/client/injection/informers/sources/v1alpha1/containersource/fake/fake.go new file mode 100644 index 00000000000..8a8f20d6848 --- /dev/null +++ b/pkg/client/injection/informers/sources/v1alpha1/containersource/fake/fake.go @@ -0,0 +1,40 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package fake + +import ( + context "context" + + fake "knative.dev/eventing/pkg/client/injection/informers/factory/fake" + containersource "knative.dev/eventing/pkg/client/injection/informers/sources/v1alpha1/containersource" + controller "knative.dev/pkg/controller" + injection "knative.dev/pkg/injection" +) + +var Get = containersource.Get + +func init() { + injection.Fake.RegisterInformer(withInformer) +} + +func withInformer(ctx context.Context) (context.Context, controller.Informer) { + f := fake.Get(ctx) + inf := f.Sources().V1alpha1().ContainerSources() + return context.WithValue(ctx, containersource.Key{}, inf), inf.Informer() +} diff --git a/pkg/client/injection/reconciler/sources/v1alpha1/containersource/controller.go b/pkg/client/injection/reconciler/sources/v1alpha1/containersource/controller.go new file mode 100644 index 00000000000..abfd2637daf --- /dev/null +++ b/pkg/client/injection/reconciler/sources/v1alpha1/containersource/controller.go @@ -0,0 +1,97 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package containersource + +import ( + context "context" + + corev1 "k8s.io/api/core/v1" + watch "k8s.io/apimachinery/pkg/watch" + scheme "k8s.io/client-go/kubernetes/scheme" + v1 "k8s.io/client-go/kubernetes/typed/core/v1" + record "k8s.io/client-go/tools/record" + versionedscheme "knative.dev/eventing/pkg/client/clientset/versioned/scheme" + injectionclient "knative.dev/eventing/pkg/client/injection/client" + containersource "knative.dev/eventing/pkg/client/injection/informers/sources/v1alpha1/containersource" + client "knative.dev/pkg/client/injection/kube/client" + controller "knative.dev/pkg/controller" + logging "knative.dev/pkg/logging" +) + +const ( + defaultControllerAgentName = "containersource-controller" + defaultFinalizerName = "containersources.sources.knative.dev" + defaultQueueName = "containersources" +) + +// NewImpl returns a controller.Impl that handles queuing and feeding work from +// the queue through an implementation of controller.Reconciler, delegating to +// the provided Interface and optional Finalizer methods. OptionsFn is used to return +// controller.Options to be used but the internal reconciler. +func NewImpl(ctx context.Context, r Interface, optionsFns ...controller.OptionsFn) *controller.Impl { + logger := logging.FromContext(ctx) + + // Check the options function input. It should be 0 or 1. + if len(optionsFns) > 1 { + logger.Fatalf("up to one options function is supported, found %d", len(optionsFns)) + } + + containersourceInformer := containersource.Get(ctx) + + recorder := controller.GetEventRecorder(ctx) + if recorder == nil { + // Create event broadcaster + logger.Debug("Creating event broadcaster") + eventBroadcaster := record.NewBroadcaster() + watches := []watch.Interface{ + eventBroadcaster.StartLogging(logger.Named("event-broadcaster").Infof), + eventBroadcaster.StartRecordingToSink( + &v1.EventSinkImpl{Interface: client.Get(ctx).CoreV1().Events("")}), + } + recorder = eventBroadcaster.NewRecorder(scheme.Scheme, corev1.EventSource{Component: defaultControllerAgentName}) + go func() { + <-ctx.Done() + for _, w := range watches { + w.Stop() + } + }() + } + + rec := &reconcilerImpl{ + Client: injectionclient.Get(ctx), + Lister: containersourceInformer.Lister(), + Recorder: recorder, + reconciler: r, + } + impl := controller.NewImpl(rec, logger, defaultQueueName) + + // Pass impl to the options. Save any optional results. + for _, fn := range optionsFns { + opts := fn(impl) + if opts.ConfigStore != nil { + rec.configStore = opts.ConfigStore + } + } + + return impl +} + +func init() { + versionedscheme.AddToScheme(scheme.Scheme) +} diff --git a/pkg/client/injection/reconciler/sources/v1alpha1/containersource/reconciler.go b/pkg/client/injection/reconciler/sources/v1alpha1/containersource/reconciler.go new file mode 100644 index 00000000000..fe9b234a4cf --- /dev/null +++ b/pkg/client/injection/reconciler/sources/v1alpha1/containersource/reconciler.go @@ -0,0 +1,323 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package containersource + +import ( + context "context" + "encoding/json" + "reflect" + + zap "go.uber.org/zap" + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/equality" + errors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + sets "k8s.io/apimachinery/pkg/util/sets" + cache "k8s.io/client-go/tools/cache" + record "k8s.io/client-go/tools/record" + v1alpha1 "knative.dev/eventing/pkg/apis/sources/v1alpha1" + versioned "knative.dev/eventing/pkg/client/clientset/versioned" + sourcesv1alpha1 "knative.dev/eventing/pkg/client/listers/sources/v1alpha1" + controller "knative.dev/pkg/controller" + logging "knative.dev/pkg/logging" + reconciler "knative.dev/pkg/reconciler" +) + +// Interface defines the strongly typed interfaces to be implemented by a +// controller reconciling v1alpha1.ContainerSource. +type Interface interface { + // ReconcileKind implements custom logic to reconcile v1alpha1.ContainerSource. Any changes + // to the objects .Status or .Finalizers will be propagated to the stored + // object. It is recommended that implementors do not call any update calls + // for the Kind inside of ReconcileKind, it is the responsibility of the calling + // controller to propagate those properties. The resource passed to ReconcileKind + // will always have an empty deletion timestamp. + ReconcileKind(ctx context.Context, o *v1alpha1.ContainerSource) reconciler.Event +} + +// Finalizer defines the strongly typed interfaces to be implemented by a +// controller finalizing v1alpha1.ContainerSource. +type Finalizer interface { + // FinalizeKind implements custom logic to finalize v1alpha1.ContainerSource. Any changes + // to the objects .Status or .Finalizers will be ignored. Returning a nil or + // Normal type reconciler.Event will allow the finalizer to be deleted on + // the resource. The resource passed to FinalizeKind will always have a set + // deletion timestamp. + FinalizeKind(ctx context.Context, o *v1alpha1.ContainerSource) reconciler.Event +} + +// reconcilerImpl implements controller.Reconciler for v1alpha1.ContainerSource resources. +type reconcilerImpl struct { + // Client is used to write back status updates. + Client versioned.Interface + + // Listers index properties about resources + Lister sourcesv1alpha1.ContainerSourceLister + + // Recorder is an event recorder for recording Event resources to the + // Kubernetes API. + Recorder record.EventRecorder + + // configStore allows for decorating a context with config maps. + // +optional + configStore reconciler.ConfigStore + + // reconciler is the implementation of the business logic of the resource. + reconciler Interface +} + +// Check that our Reconciler implements controller.Reconciler +var _ controller.Reconciler = (*reconcilerImpl)(nil) + +func NewReconciler(ctx context.Context, logger *zap.SugaredLogger, client versioned.Interface, lister sourcesv1alpha1.ContainerSourceLister, recorder record.EventRecorder, r Interface, options ...controller.Options) controller.Reconciler { + // Check the options function input. It should be 0 or 1. + if len(options) > 1 { + logger.Fatalf("up to one options struct is supported, found %d", len(options)) + } + + rec := &reconcilerImpl{ + Client: client, + Lister: lister, + Recorder: recorder, + reconciler: r, + } + + for _, opts := range options { + if opts.ConfigStore != nil { + rec.configStore = opts.ConfigStore + } + } + + return rec +} + +// Reconcile implements controller.Reconciler +func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { + logger := logging.FromContext(ctx) + + // If configStore is set, attach the frozen configuration to the context. + if r.configStore != nil { + ctx = r.configStore.ToContext(ctx) + } + + // Add the recorder to context. + ctx = controller.WithEventRecorder(ctx, r.Recorder) + + // Convert the namespace/name string into a distinct namespace and name + namespace, name, err := cache.SplitMetaNamespaceKey(key) + if err != nil { + logger.Errorf("invalid resource key: %s", key) + return nil + } + + // Get the resource with this namespace/name. + original, err := r.Lister.ContainerSources(namespace).Get(name) + if errors.IsNotFound(err) { + // The resource may no longer exist, in which case we stop processing. + logger.Errorf("resource %q no longer exists", key) + return nil + } else if err != nil { + return err + } + + // Don't modify the informers copy. + resource := original.DeepCopy() + + var reconcileEvent reconciler.Event + if resource.GetDeletionTimestamp().IsZero() { + // Append the target method to the logger. + logger = logger.With(zap.String("targetMethod", "ReconcileKind")) + + // Set and update the finalizer on resource if r.reconciler + // implements Finalizer. + if resource, err = r.setFinalizerIfFinalizer(ctx, resource); err != nil { + logger.Warnw("Failed to set finalizers", zap.Error(err)) + } + + // Reconcile this copy of the resource and then write back any status + // updates regardless of whether the reconciliation errored out. + reconcileEvent = r.reconciler.ReconcileKind(ctx, resource) + } else if fin, ok := r.reconciler.(Finalizer); ok { + // Append the target method to the logger. + logger = logger.With(zap.String("targetMethod", "FinalizeKind")) + + // For finalizing reconcilers, if this resource being marked for deletion + // and reconciled cleanly (nil or normal event), remove the finalizer. + reconcileEvent = fin.FinalizeKind(ctx, resource) + if resource, err = r.clearFinalizer(ctx, resource, reconcileEvent); err != nil { + logger.Warnw("Failed to clear finalizers", zap.Error(err)) + } + } + + // Synchronize the status. + if equality.Semantic.DeepEqual(original.Status, resource.Status) { + // If we didn't change anything then don't call updateStatus. + // This is important because the copy we loaded from the injectionInformer's + // cache may be stale and we don't want to overwrite a prior update + // to status with this stale state. + } else if err = r.updateStatus(original, resource); err != nil { + logger.Warnw("Failed to update resource status", zap.Error(err)) + r.Recorder.Eventf(resource, v1.EventTypeWarning, "UpdateFailed", + "Failed to update status for %q: %v", resource.Name, err) + return err + } + + // Report the reconciler event, if any. + if reconcileEvent != nil { + var event *reconciler.ReconcilerEvent + if reconciler.EventAs(reconcileEvent, &event) { + logger.Infow("returned an event", zap.Any("event", reconcileEvent)) + r.Recorder.Eventf(resource, event.EventType, event.Reason, event.Format, event.Args...) + return nil + } else { + logger.Errorw("returned an error", zap.Error(reconcileEvent)) + r.Recorder.Event(resource, v1.EventTypeWarning, "InternalError", reconcileEvent.Error()) + return reconcileEvent + } + } + return nil +} + +func (r *reconcilerImpl) updateStatus(existing *v1alpha1.ContainerSource, desired *v1alpha1.ContainerSource) error { + existing = existing.DeepCopy() + return reconciler.RetryUpdateConflicts(func(attempts int) (err error) { + // The first iteration tries to use the injectionInformer's state, subsequent attempts fetch the latest state via API. + if attempts > 0 { + existing, err = r.Client.SourcesV1alpha1().ContainerSources(desired.Namespace).Get(desired.Name, metav1.GetOptions{}) + if err != nil { + return err + } + } + + // If there's nothing to update, just return. + if reflect.DeepEqual(existing.Status, desired.Status) { + return nil + } + + existing.Status = desired.Status + _, err = r.Client.SourcesV1alpha1().ContainerSources(existing.Namespace).UpdateStatus(existing) + return err + }) +} + +// updateFinalizersFiltered will update the Finalizers of the resource. +// TODO: this method could be generic and sync all finalizers. For now it only +// updates defaultFinalizerName. +func (r *reconcilerImpl) updateFinalizersFiltered(ctx context.Context, resource *v1alpha1.ContainerSource) (*v1alpha1.ContainerSource, error) { + finalizerName := defaultFinalizerName + + actual, err := r.Lister.ContainerSources(resource.Namespace).Get(resource.Name) + if err != nil { + return resource, err + } + + // Don't modify the informers copy. + existing := actual.DeepCopy() + + var finalizers []string + + // If there's nothing to update, just return. + existingFinalizers := sets.NewString(existing.Finalizers...) + desiredFinalizers := sets.NewString(resource.Finalizers...) + + if desiredFinalizers.Has(finalizerName) { + if existingFinalizers.Has(finalizerName) { + // Nothing to do. + return resource, nil + } + // Add the finalizer. + finalizers = append(existing.Finalizers, finalizerName) + } else { + if !existingFinalizers.Has(finalizerName) { + // Nothing to do. + return resource, nil + } + // Remove the finalizer. + existingFinalizers.Delete(finalizerName) + finalizers = existingFinalizers.List() + } + + mergePatch := map[string]interface{}{ + "metadata": map[string]interface{}{ + "finalizers": finalizers, + "resourceVersion": existing.ResourceVersion, + }, + } + + patch, err := json.Marshal(mergePatch) + if err != nil { + return resource, err + } + + resource, err = r.Client.SourcesV1alpha1().ContainerSources(resource.Namespace).Patch(resource.Name, types.MergePatchType, patch) + if err != nil { + r.Recorder.Eventf(resource, v1.EventTypeWarning, "FinalizerUpdateFailed", + "Failed to update finalizers for %q: %v", resource.Name, err) + } else { + r.Recorder.Eventf(resource, v1.EventTypeNormal, "FinalizerUpdate", + "Updated %q finalizers", resource.GetName()) + } + return resource, err +} + +func (r *reconcilerImpl) setFinalizerIfFinalizer(ctx context.Context, resource *v1alpha1.ContainerSource) (*v1alpha1.ContainerSource, error) { + if _, ok := r.reconciler.(Finalizer); !ok { + return resource, nil + } + + finalizers := sets.NewString(resource.Finalizers...) + + // If this resource is not being deleted, mark the finalizer. + if resource.GetDeletionTimestamp().IsZero() { + finalizers.Insert(defaultFinalizerName) + } + + resource.Finalizers = finalizers.List() + + // Synchronize the finalizers filtered by defaultFinalizerName. + return r.updateFinalizersFiltered(ctx, resource) +} + +func (r *reconcilerImpl) clearFinalizer(ctx context.Context, resource *v1alpha1.ContainerSource, reconcileEvent reconciler.Event) (*v1alpha1.ContainerSource, error) { + if _, ok := r.reconciler.(Finalizer); !ok { + return resource, nil + } + if resource.GetDeletionTimestamp().IsZero() { + return resource, nil + } + + finalizers := sets.NewString(resource.Finalizers...) + + if reconcileEvent != nil { + var event *reconciler.ReconcilerEvent + if reconciler.EventAs(reconcileEvent, &event) { + if event.EventType == v1.EventTypeNormal { + finalizers.Delete(defaultFinalizerName) + } + } + } else { + finalizers.Delete(defaultFinalizerName) + } + + resource.Finalizers = finalizers.List() + + // Synchronize the finalizers filtered by defaultFinalizerName. + return r.updateFinalizersFiltered(ctx, resource) +} diff --git a/pkg/client/injection/reconciler/sources/v1alpha1/containersource/stub/controller.go b/pkg/client/injection/reconciler/sources/v1alpha1/containersource/stub/controller.go new file mode 100644 index 00000000000..08a2140e82d --- /dev/null +++ b/pkg/client/injection/reconciler/sources/v1alpha1/containersource/stub/controller.go @@ -0,0 +1,54 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package containersource + +import ( + context "context" + + containersource "knative.dev/eventing/pkg/client/injection/informers/sources/v1alpha1/containersource" + v1alpha1containersource "knative.dev/eventing/pkg/client/injection/reconciler/sources/v1alpha1/containersource" + configmap "knative.dev/pkg/configmap" + controller "knative.dev/pkg/controller" + logging "knative.dev/pkg/logging" +) + +// TODO: PLEASE COPY AND MODIFY THIS FILE AS A STARTING POINT + +// NewController creates a Reconciler for ContainerSource and returns the result of NewImpl. +func NewController( + ctx context.Context, + cmw configmap.Watcher, +) *controller.Impl { + logger := logging.FromContext(ctx) + + containersourceInformer := containersource.Get(ctx) + + // TODO: setup additional informers here. + + r := &Reconciler{} + impl := v1alpha1containersource.NewImpl(ctx, r) + + logger.Info("Setting up event handlers.") + + containersourceInformer.Informer().AddEventHandler(controller.HandleAll(impl.Enqueue)) + + // TODO: add additional informer event handlers here. + + return impl +} diff --git a/pkg/client/injection/reconciler/sources/v1alpha1/containersource/stub/reconciler.go b/pkg/client/injection/reconciler/sources/v1alpha1/containersource/stub/reconciler.go new file mode 100644 index 00000000000..e7a65f3913c --- /dev/null +++ b/pkg/client/injection/reconciler/sources/v1alpha1/containersource/stub/reconciler.go @@ -0,0 +1,64 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package containersource + +import ( + context "context" + + v1 "k8s.io/api/core/v1" + v1alpha1 "knative.dev/eventing/pkg/apis/sources/v1alpha1" + containersource "knative.dev/eventing/pkg/client/injection/reconciler/sources/v1alpha1/containersource" + reconciler "knative.dev/pkg/reconciler" +) + +// TODO: PLEASE COPY AND MODIFY THIS FILE AS A STARTING POINT + +// newReconciledNormal makes a new reconciler event with event type Normal, and +// reason ContainerSourceReconciled. +func newReconciledNormal(namespace, name string) reconciler.Event { + return reconciler.NewEvent(v1.EventTypeNormal, "ContainerSourceReconciled", "ContainerSource reconciled: \"%s/%s\"", namespace, name) +} + +// Reconciler implements controller.Reconciler for ContainerSource resources. +type Reconciler struct { + // TODO: add additional requirements here. +} + +// Check that our Reconciler implements Interface +var _ containersource.Interface = (*Reconciler)(nil) + +// Optionally check that our Reconciler implements Finalizer +//var _ containersource.Finalizer = (*Reconciler)(nil) + +// ReconcileKind implements Interface.ReconcileKind. +func (r *Reconciler) ReconcileKind(ctx context.Context, o *v1alpha1.ContainerSource) reconciler.Event { + o.Status.InitializeConditions() + + // TODO: add custom reconciliation logic here. + + o.Status.ObservedGeneration = o.Generation + return newReconciledNormal(o.Namespace, o.Name) +} + +// Optionally, use FinalizeKind to add finalizers. FinalizeKind will be called +// when the resource is deleted. +//func (r *Reconciler) FinalizeKind(ctx context.Context, o *v1alpha1.ContainerSource) reconciler.Event { +// // TODO: add custom finalization logic here. +// return nil +//} diff --git a/pkg/client/listers/sources/v1alpha1/containersource.go b/pkg/client/listers/sources/v1alpha1/containersource.go new file mode 100644 index 00000000000..8ac0cddfce8 --- /dev/null +++ b/pkg/client/listers/sources/v1alpha1/containersource.go @@ -0,0 +1,94 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" + v1alpha1 "knative.dev/eventing/pkg/apis/sources/v1alpha1" +) + +// 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 f30287719ed..38f878705a5 100644 --- a/pkg/client/listers/sources/v1alpha1/expansion_generated.go +++ b/pkg/client/listers/sources/v1alpha1/expansion_generated.go @@ -26,6 +26,14 @@ type ApiServerSourceListerExpansion interface{} // ApiServerSourceNamespaceLister. type ApiServerSourceNamespaceListerExpansion interface{} +// ContainerSourceListerExpansion allows custom methods to be added to +// ContainerSourceLister. +type ContainerSourceListerExpansion interface{} + +// ContainerSourceNamespaceListerExpansion allows custom methods to be added to +// ContainerSourceNamespaceLister. +type ContainerSourceNamespaceListerExpansion interface{} + // PingSourceListerExpansion allows custom methods to be added to // PingSourceLister. type PingSourceListerExpansion interface{} diff --git a/pkg/reconciler/containersource/containersource.go b/pkg/reconciler/containersource/containersource.go new file mode 100644 index 00000000000..0db7ee69542 --- /dev/null +++ b/pkg/reconciler/containersource/containersource.go @@ -0,0 +1,168 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package containersource + +import ( + "context" + "encoding/json" + "fmt" + + "go.uber.org/zap" + "k8s.io/apimachinery/pkg/api/equality" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "knative.dev/eventing/pkg/logging" + "knative.dev/pkg/apis" + "knative.dev/pkg/resolver" + + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" + appsv1listers "k8s.io/client-go/listers/apps/v1" + "knative.dev/eventing/pkg/apis/sources/v1alpha1" + "knative.dev/eventing/pkg/client/injection/reconciler/sources/v1alpha1/containersource" + listers "knative.dev/eventing/pkg/client/listers/sources/v1alpha1" + "knative.dev/eventing/pkg/reconciler/containersource/resources" + duckv1 "knative.dev/pkg/apis/duck/v1" + pkgreconciler "knative.dev/pkg/reconciler" +) + +// newReconciledNormal makes a new reconciler event with event type Normal, and +// reason ContainerSourceReconciled. +func newReconciledNormal(namespace, name string) pkgreconciler.Event { + return pkgreconciler.NewEvent(corev1.EventTypeNormal, "ContainerSourceReconciled", "ContainerSource reconciled: \"%s/%s\"", namespace, name) +} + +func newWarningSinkNotFound(sink *duckv1.Destination) pkgreconciler.Event { + b, _ := json.Marshal(sink) + return pkgreconciler.NewEvent(corev1.EventTypeWarning, "SinkNotFound", "Sink not found: %s", string(b)) +} + +// Reconciler implements controller.Reconciler for ContainerSource resources. +type Reconciler struct { + kubeClientSet kubernetes.Interface + + // listers index properties about resources + containerSourceLister listers.ContainerSourceLister + deploymentLister appsv1listers.DeploymentLister + + sinkResolver *resolver.URIResolver +} + +// Check that our Reconciler implements Interface +var _ containersource.Interface = (*Reconciler)(nil) + +// Optionally check that our Reconciler implements Finalizer +//var _ containersource.Finalizer = (*Reconciler)(nil) + +// ReconcileKind implements Interface.ReconcileKind. +func (r *Reconciler) ReconcileKind(ctx context.Context, source *v1alpha1.ContainerSource) pkgreconciler.Event { + source.Status.InitializeConditions() + source.Status.ObservedGeneration = source.Generation + + dest := source.Spec.Sink.DeepCopy() + if dest.Ref != nil { + // To call URIFromDestinationV1(), dest.Ref must have a Namespace. If there is + // no Namespace defined in dest.Ref, we will use the Namespace of the source + // as the Namespace of dest.Ref. + if dest.Ref.Namespace == "" { + dest.Ref.Namespace = source.GetNamespace() + } + } + + sinkURI, err := r.sinkResolver.URIFromDestinationV1(*dest, source) + if err != nil { + source.Status.MarkNoSink("SinkNotFound", "") + return newWarningSinkNotFound(dest) + } + source.Status.MarkSink(sinkURI) + + ra, err := r.reconcileReceiveAdapter(ctx, source, sinkURI) + if err != nil { + source.Status.MarkNotDeployed("DeploymentReconcileFailed", "Failed to reconcile deployment: %v", err) + return err + } + source.Status.PropagateDeploymentAvailability(ra) + return newReconciledNormal(source.Namespace, source.Name) +} + +func (r *Reconciler) reconcileReceiveAdapter(ctx context.Context, source *v1alpha1.ContainerSource, sinkURI *apis.URL) (*appsv1.Deployment, error) { + + ceOverrides := r.marshalCeOverrides(ctx, source) + args := &resources.ContainerSourceArgs{ + Source: source, + SinkURI: sinkURI, + CeOverrides: ceOverrides, + Labels: resources.Labels(source.Name), + } + expected := resources.MakeDeployment(args) + + ra, err := r.deploymentLister.Deployments(expected.Namespace).Get(expected.Name) + if apierrors.IsNotFound(err) { + ra, err = r.kubeClientSet.AppsV1().Deployments(expected.Namespace).Create(expected) + if err != nil { + return nil, fmt.Errorf("creating new deployment: %v", err) + } + return ra, nil + } else if err != nil { + return nil, fmt.Errorf("getting deployment: %v", err) + } else if !metav1.IsControlledBy(ra, source) { + return nil, fmt.Errorf("deployment %q is not owned by ContainerSource %q", ra.Name, source.Name) + } else if r.podSpecChanged(ra.Spec.Template.Spec, expected.Spec.Template.Spec) { + ra.Spec.Template.Spec = expected.Spec.Template.Spec + ra, err = r.kubeClientSet.AppsV1().Deployments(expected.Namespace).Update(ra) + if err != nil { + return ra, fmt.Errorf("updating deployment: %v", err) + } + return ra, nil + } else { + logging.FromContext(ctx).Debug("Reusing existing receive adapter", zap.Any("receiveAdapter", ra)) + } + return ra, nil +} + +func (r *Reconciler) podSpecChanged(oldPodSpec corev1.PodSpec, newPodSpec corev1.PodSpec) bool { + // 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 newPodSpec. + 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) marshalCeOverrides(ctx context.Context, source *v1alpha1.ContainerSource) string { + var ceOverrides string + if source.Spec.CloudEventOverrides != nil { + if co, err := json.Marshal(source.Spec.CloudEventOverrides); err != nil { + logging.FromContext(ctx).Error("Failed to marshal CloudEventOverrides into JSON", zap.Any("source", source), zap.Error(err)) + } else if len(co) > 0 { + ceOverrides = string(co) + } + } + return ceOverrides +} diff --git a/pkg/reconciler/containersource/containersource_test.go b/pkg/reconciler/containersource/containersource_test.go new file mode 100644 index 00000000000..cbb9c983003 --- /dev/null +++ b/pkg/reconciler/containersource/containersource_test.go @@ -0,0 +1,420 @@ +/* +Copyright 2020 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" + "fmt" + "testing" + + "knative.dev/pkg/apis" + "knative.dev/pkg/logging" + "knative.dev/pkg/resolver" + + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/kubernetes/scheme" + clientgotesting "k8s.io/client-go/testing" + fakeeventingclient "knative.dev/eventing/pkg/client/injection/client/fake" + fakekubeclient "knative.dev/pkg/client/injection/kube/client/fake" + + "knative.dev/eventing/pkg/client/injection/reconciler/sources/v1alpha1/containersource" + "knative.dev/eventing/pkg/reconciler/containersource/resources" + duckv1 "knative.dev/pkg/apis/duck/v1" + "knative.dev/pkg/client/injection/ducks/duck/v1/addressable" + _ "knative.dev/pkg/client/injection/ducks/duck/v1/addressable/fake" + "knative.dev/pkg/configmap" + "knative.dev/pkg/controller" + + sourcesv1alpha1 "knative.dev/eventing/pkg/apis/sources/v1alpha1" + "knative.dev/eventing/pkg/utils" + + logtesting "knative.dev/pkg/logging/testing" + . "knative.dev/pkg/reconciler/testing" + + . "knative.dev/eventing/pkg/reconciler/testing" +) + +const ( + image = "github.com/knative/test/image" + sourceName = "test-container-source" + sourceUID = "1234-5678-90" + testNS = "testnamespace" + sinkName = "testsink" + generation = 1 +) + +var ( + trueVal = true + + nonsinkDest = duckv1.Destination{ + Ref: &duckv1.KReference{ + Name: sinkName, + Kind: "Trigger", + APIVersion: "eventing.knative.dev/v1alpha1", + }, + } + nonsinkDestWithNamespace = duckv1.Destination{ + Ref: &duckv1.KReference{ + Name: sinkName, + Namespace: testNS, + Kind: "Trigger", + APIVersion: "eventing.knative.dev/v1alpha1", + }, + } + + deploymentName = fmt.Sprintf("containersource-%s-%s", sourceName, sourceUID) + + // We cannot take the address of constants, so copy it into a var. + conditionTrue = corev1.ConditionTrue + + serviceDest = duckv1.Destination{ + Ref: &duckv1.KReference{ + Name: sinkName, + Kind: "Service", + APIVersion: "v1", + }, + } + serviceURI = fmt.Sprintf("http://%s.%s.svc.cluster.local/", sinkName, testNS) + + sinkDest = duckv1.Destination{ + Ref: &duckv1.KReference{ + Name: sinkName, + Kind: "Channel", + APIVersion: "messaging.knative.dev/v1alpha1", + }, + } + sinkDestWithNamespace = duckv1.Destination{ + Ref: &duckv1.KReference{ + Name: sinkName, + Namespace: testNS, + Kind: "Channel", + APIVersion: "messaging.knative.dev/v1alpha1", + }, + } + sinkDNS = "sink.mynamespace.svc." + utils.GetClusterDomainName() + sinkURI = apis.HTTP(sinkDNS) + sinkDestURI = duckv1.Destination{ + URI: apis.HTTP(sinkDNS), + } +) + +func init() { + // Add types to scheme + _ = appsv1.AddToScheme(scheme.Scheme) + _ = corev1.AddToScheme(scheme.Scheme) + _ = duckv1.AddToScheme(scheme.Scheme) +} + +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", + }, { + Name: "missing sink", + Objects: []runtime.Object{ + NewContainerSource(sourceName, testNS, + WithContainerSourceSpec(makeContainerSourceSpec(sinkDest)), + WithContainerSourceObjectMetaGeneration(generation), + ), + }, + Key: testNS + "/" + sourceName, + WantEvents: []string{ + Eventf(corev1.EventTypeWarning, "SinkNotFound", `Sink not found: {"ref":{"kind":"Channel","namespace":"testnamespace","name":"testsink","apiVersion":"messaging.knative.dev/v1alpha1"}}`), + }, + WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ + Object: NewContainerSource(sourceName, testNS, + WithContainerSourceSpec(makeContainerSourceSpec(sinkDest)), + WithContainerSourceObjectMetaGeneration(generation), + // Status Update: + WithInitContainerSourceConditions, + WithContainerSourceStatusObservedGeneration(generation), + WithContainerSourceSinkNotFound(""), + ), + }}, + }, { + Name: "sink not addressable", + Objects: []runtime.Object{ + NewContainerSource(sourceName, testNS, + WithContainerSourceSpec(makeContainerSourceSpec(nonsinkDest)), + WithContainerSourceObjectMetaGeneration(generation), + ), + NewTrigger(sinkName, testNS, ""), + }, + Key: testNS + "/" + sourceName, + WantEvents: []string{ + Eventf(corev1.EventTypeWarning, "SinkNotFound", `Sink not found: {"ref":{"kind":"Trigger","namespace":"testnamespace","name":"testsink","apiVersion":"eventing.knative.dev/v1alpha1"}}`), + }, + WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ + Object: NewContainerSource(sourceName, testNS, + WithContainerSourceSpec(makeContainerSourceSpec(nonsinkDest)), + WithContainerSourceObjectMetaGeneration(generation), + // Status Update: + WithInitContainerSourceConditions, + WithContainerSourceStatusObservedGeneration(generation), + WithContainerSourceSinkNotFound(""), + ), + }}, + }, { + Name: "sink not ready", + Objects: []runtime.Object{ + NewContainerSource(sourceName, testNS, + WithContainerSourceSpec(makeContainerSourceSpec(sinkDest)), + WithContainerSourceObjectMetaGeneration(generation), + ), + NewChannel(sinkName, testNS), + }, + Key: testNS + "/" + sourceName, + WantEvents: []string{ + Eventf(corev1.EventTypeWarning, "SinkNotFound", `Sink not found: {"ref":{"kind":"Channel","namespace":"testnamespace","name":"testsink","apiVersion":"messaging.knative.dev/v1alpha1"}}`), + }, + WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ + Object: NewContainerSource(sourceName, testNS, + WithContainerSourceSpec(makeContainerSourceSpec(sinkDest)), + WithContainerSourceObjectMetaGeneration(generation), + // Status Update: + WithInitContainerSourceConditions, + WithContainerSourceStatusObservedGeneration(generation), + WithContainerSourceSinkNotFound(""), + ), + }}, + }, { + Name: "deployment unavailable", + Objects: []runtime.Object{ + NewContainerSource(sourceName, testNS, + WithContainerSourceSpec(makeContainerSourceSpec(sinkDest)), + WithContainerSourceObjectMetaGeneration(generation), + WithContainerSourceUID(sourceUID), + ), + NewChannel(sinkName, testNS, + WithChannelAddress(sinkDNS), + ), + }, + Key: testNS + "/" + sourceName, + WantEvents: []string{ + Eventf(corev1.EventTypeNormal, "ContainerSourceReconciled", `ContainerSource reconciled: "testnamespace/test-container-source"`), + }, + WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ + Object: NewContainerSource(sourceName, testNS, + WithContainerSourceSpec(makeContainerSourceSpec(sinkDest)), + WithContainerSourceUID(sourceUID), + WithContainerSourceObjectMetaGeneration(generation), + // Status Update: + WithInitContainerSourceConditions, + WithContainerSourceSink(sinkURI), + WithContainerSourcePropagateDeploymentAvailability( + makeDeployment(NewContainerSource(sourceName, testNS, + WithContainerSourceSpec(makeContainerSourceSpec(sinkDest)), + WithContainerSourceUID(sourceUID), + ), nil, sinkURI, "", nil, nil)), + WithContainerSourceStatusObservedGeneration(generation), + ), + }}, + WantCreates: []runtime.Object{ + makeDeployment(NewContainerSource(sourceName, testNS, + WithContainerSourceSpec(makeContainerSourceSpec(sinkDest)), + WithContainerSourceUID(sourceUID), + ), nil, sinkURI, "", nil, nil), + }, + }, { + Name: "valid with ready deployment", + Objects: []runtime.Object{ + NewContainerSource(sourceName, testNS, + WithContainerSourceSpec(makeContainerSourceSpec(sinkDest)), + WithContainerSourceUID(sourceUID), + WithContainerSourceObjectMetaGeneration(generation), + WithInitContainerSourceConditions, + WithContainerSourceSink(sinkURI), + ), + NewChannel(sinkName, testNS, + WithChannelAddress(sinkDNS), + ), + makeDeployment(NewContainerSource(sourceName, testNS, + WithContainerSourceSpec(makeContainerSourceSpec(sinkDest)), + WithContainerSourceUID(sourceUID), + ), &conditionTrue, sinkURI, "", nil, nil), + }, + Key: testNS + "/" + sourceName, + WantEvents: []string{ + Eventf(corev1.EventTypeNormal, "ContainerSourceReconciled", `ContainerSource reconciled: "testnamespace/test-container-source"`), + }, + WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ + Object: NewContainerSource(sourceName, testNS, + WithContainerSourceSpec(makeContainerSourceSpec(sinkDest)), + WithContainerSourceUID(sourceUID), + WithContainerSourceObjectMetaGeneration(generation), + WithInitContainerSourceConditions, + WithContainerSourceSink(sinkURI), + // Status Update: + WithContainerSourcePropagateDeploymentAvailability( + makeDeployment(NewContainerSource(sourceName, testNS, + WithContainerSourceSpec(makeContainerSourceSpec(sinkDest)), + WithContainerSourceUID(sourceUID), + ), &conditionTrue, sinkURI, "", nil, nil)), + WithContainerSourceStatusObservedGeneration(generation), + ), + }}, + }, { + Name: "error for create deployment", + Objects: []runtime.Object{ + NewContainerSource(sourceName, testNS, + WithContainerSourceSpec(makeContainerSourceSpec(sinkDest)), + WithContainerSourceUID(sourceUID), + WithContainerSourceObjectMetaGeneration(generation), + ), + NewChannel(sinkName, testNS, + WithChannelAddress(sinkDNS), + ), + }, + Key: testNS + "/" + sourceName, + WantErr: true, + WantEvents: []string{ + Eventf(corev1.EventTypeWarning, "InternalError", "creating new deployment: inducing failure for create deployments"), + }, + WithReactors: []clientgotesting.ReactionFunc{ + InduceFailure("create", "deployments"), + }, + WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ + Object: NewContainerSource(sourceName, testNS, + WithContainerSourceSpec(makeContainerSourceSpec(sinkDest)), + WithContainerSourceUID(sourceUID), + WithContainerSourceObjectMetaGeneration(generation), + // Status Update: + WithInitContainerSourceConditions, + WithContainerSourceStatusObservedGeneration(generation), + WithContainerSourceSink(sinkURI), + WithContainerSourceDeployFailed(`Failed to reconcile deployment: creating new deployment: inducing failure for create deployments`), + ), + }}, + WantCreates: []runtime.Object{ + makeDeployment(NewContainerSource(sourceName, testNS, + WithContainerSourceSpec(makeContainerSourceSpec(sinkDest)), + WithContainerSourceUID(sourceUID), + ), nil, sinkURI, "", nil, nil), + }, + }, + } + + logger := logtesting.TestLogger(t) + table.Test(t, MakeFactory(func(ctx context.Context, listers *Listers, cmw configmap.Watcher) controller.Reconciler { + ctx = addressable.WithDuck(ctx) + r := &Reconciler{ + kubeClientSet: fakekubeclient.Get(ctx), + containerSourceLister: listers.GetContainerSourceLister(), + deploymentLister: listers.GetDeploymentLister(), + sinkResolver: resolver.NewURIResolver(ctx, func(types.NamespacedName) {}), + } + return containersource.NewReconciler(ctx, logging.FromContext(ctx), fakeeventingclient.Get(ctx), listers.GetContainerSourceLister(), controller.GetEventRecorder(ctx), r) + }, + true, + logger, + )) +} + +func makeDeployment(source *sourcesv1alpha1.ContainerSource, available *corev1.ConditionStatus, sinkURI *apis.URL, ceOverrides string, labels map[string]string, annotations map[string]string) *appsv1.Deployment { + template := source.Spec.Template + + for i := range template.Spec.Containers { + template.Spec.Containers[i].Env = append(template.Spec.Containers[i].Env, corev1.EnvVar{ + Name: "K_SINK", + Value: sinkURI.String(), + }) + template.Spec.Containers[i].Env = append(template.Spec.Containers[i].Env, corev1.EnvVar{ + Name: "K_CE_OVERRIDES", + Value: ceOverrides, + }) + } + + if template.Labels == nil { + template.Labels = make(map[string]string) + } + for k, v := range resources.Labels(source.Name) { + template.Labels[k] = v + } + + status := appsv1.DeploymentStatus{} + if available != nil { + status.Conditions = []appsv1.DeploymentCondition{ + { + Type: appsv1.DeploymentAvailable, + Status: *available, + }, + } + if *available == corev1.ConditionTrue { + status.ReadyReplicas = 1 + } + } + + return &appsv1.Deployment{ + TypeMeta: metav1.TypeMeta{ + APIVersion: appsv1.SchemeGroupVersion.String(), + Kind: "Deployment", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: deploymentName, + Namespace: source.Namespace, + OwnerReferences: getOwnerReferences(), + Labels: resources.Labels(source.Name), + }, + Spec: appsv1.DeploymentSpec{ + Selector: &metav1.LabelSelector{ + MatchLabels: resources.Labels(source.Name), + }, + Template: template, + }, + Status: status, + } +} + +func getOwnerReferences() []metav1.OwnerReference { + return []metav1.OwnerReference{{ + APIVersion: sourcesv1alpha1.SchemeGroupVersion.String(), + Kind: "ContainerSource", + Name: sourceName, + Controller: &trueVal, + BlockOwnerDeletion: &trueVal, + UID: sourceUID, + }} +} + +func makeContainerSourceSpec(sink duckv1.Destination) sourcesv1alpha1.ContainerSourceSpec { + return sourcesv1alpha1.ContainerSourceSpec{ + Template: corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + { + Name: "source", + Image: image, + ImagePullPolicy: corev1.PullIfNotPresent, + }, + }, + }, + }, + SourceSpec: duckv1.SourceSpec{ + Sink: sink, + }, + } +} diff --git a/pkg/reconciler/containersource/controller.go b/pkg/reconciler/containersource/controller.go new file mode 100644 index 00000000000..01ae9e0b970 --- /dev/null +++ b/pkg/reconciler/containersource/controller.go @@ -0,0 +1,71 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package containersource + +import ( + "context" + + "k8s.io/client-go/tools/cache" + "knative.dev/pkg/logging" + "knative.dev/pkg/resolver" + + "knative.dev/eventing/pkg/apis/sources/v1alpha1" + "knative.dev/eventing/pkg/client/injection/informers/sources/v1alpha1/containersource" + v1alpha1containersource "knative.dev/eventing/pkg/client/injection/reconciler/sources/v1alpha1/containersource" + kubeclient "knative.dev/pkg/client/injection/kube/client" + deploymentinformer "knative.dev/pkg/client/injection/kube/informers/apps/v1/deployment" + "knative.dev/pkg/configmap" + "knative.dev/pkg/controller" +) + +const ( + // controllerAgentName is the string used by this controller to identify + // itself when creating events. + controllerAgentName = "container-source-controller" +) + +// NewController creates a Reconciler for ContainerSource and returns the result of NewImpl. +func NewController( + ctx context.Context, + cmw configmap.Watcher, +) *controller.Impl { + + kubeClient := kubeclient.Get(ctx) + + containersourceInformer := containersource.Get(ctx) + deploymentInformer := deploymentinformer.Get(ctx) + + r := &Reconciler{ + kubeClientSet: kubeClient, + containerSourceLister: containersourceInformer.Lister(), + deploymentLister: deploymentInformer.Lister(), + } + impl := v1alpha1containersource.NewImpl(ctx, r) + r.sinkResolver = resolver.NewURIResolver(ctx, impl.EnqueueKey) + + logging.FromContext(ctx).Info("Setting up event handlers.") + containersourceInformer.Informer().AddEventHandler(controller.HandleAll(impl.Enqueue)) + + deploymentInformer.Informer().AddEventHandler(cache.FilteringResourceEventHandler{ + FilterFunc: controller.FilterGroupVersionKind(v1alpha1.SchemeGroupVersion.WithKind("ContainerSource")), + Handler: controller.HandleAll(impl.EnqueueControllerOf), + }) + + return impl +} diff --git a/pkg/reconciler/containersource/controller_test.go b/pkg/reconciler/containersource/controller_test.go new file mode 100644 index 00000000000..d1025057e5e --- /dev/null +++ b/pkg/reconciler/containersource/controller_test.go @@ -0,0 +1,41 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package containersource + +import ( + "testing" + + "knative.dev/pkg/configmap" + . "knative.dev/pkg/reconciler/testing" + + // Fake injection informers + _ "knative.dev/eventing/pkg/client/injection/informers/sources/v1alpha1/containersource/fake" + "knative.dev/pkg/client/injection/ducks/duck/v1/addressable" + _ "knative.dev/pkg/client/injection/kube/informers/apps/v1/deployment/fake" + _ "knative.dev/pkg/injection/clients/dynamicclient/fake" +) + +func TestNew(t *testing.T) { + ctx, _ := SetupFakeContext(t) + ctx = addressable.WithDuck(ctx) + + c := NewController(ctx, configmap.NewStaticWatcher()) + + if c == nil { + t.Fatal("Expected NewController to return a non-nil value") + } +} diff --git a/pkg/reconciler/containersource/resources/deployment.go b/pkg/reconciler/containersource/resources/deployment.go new file mode 100644 index 00000000000..524ca2648f9 --- /dev/null +++ b/pkg/reconciler/containersource/resources/deployment.go @@ -0,0 +1,80 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package resources + +import ( + "fmt" + + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "knative.dev/eventing/pkg/apis/sources/v1alpha1" + "knative.dev/pkg/apis" + "knative.dev/pkg/kmeta" +) + +type ContainerSourceArgs struct { + Source *v1alpha1.ContainerSource + SinkURI *apis.URL + CeOverrides string + Labels map[string]string +} + +func MakeDeployment(args *ContainerSourceArgs) *appsv1.Deployment { + template := args.Source.Spec.Template + + for i := range template.Spec.Containers { + template.Spec.Containers[i].Env = append(template.Spec.Containers[i].Env, corev1.EnvVar{ + Name: "K_SINK", + Value: args.SinkURI.String(), + }) + template.Spec.Containers[i].Env = append(template.Spec.Containers[i].Env, corev1.EnvVar{ + Name: "K_CE_OVERRIDES", + Value: args.CeOverrides, + }) + } + + if template.Labels == nil { + template.Labels = make(map[string]string) + } + for k, v := range args.Labels { + template.Labels[k] = v + } + + deploy := &appsv1.Deployment{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "apps/v1", + Kind: "Deployment", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: kmeta.ChildName(fmt.Sprintf("containersource-%s-", args.Source.Name), string(args.Source.UID)), + Namespace: args.Source.Namespace, + OwnerReferences: []metav1.OwnerReference{ + *kmeta.NewControllerRef(args.Source), + }, + Labels: args.Labels, + }, + Spec: appsv1.DeploymentSpec{ + Selector: &metav1.LabelSelector{ + MatchLabels: args.Labels, + }, + Template: template, + }, + } + return deploy +} diff --git a/pkg/reconciler/containersource/resources/deployment_test.go b/pkg/reconciler/containersource/resources/deployment_test.go new file mode 100644 index 00000000000..60b9f20036f --- /dev/null +++ b/pkg/reconciler/containersource/resources/deployment_test.go @@ -0,0 +1,330 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package resources + +import ( + "fmt" + "knative.dev/pkg/apis" + "testing" + + "knative.dev/eventing/pkg/apis/sources/v1alpha1" + + "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" + duckv1 "knative.dev/pkg/apis/duck/v1" +) + +const ( + name = "test-name" + uid = "uid" +) + +func TestMakeDeployment(t *testing.T) { + yes := true + tests := []struct { + name string + args ContainerSourceArgs + want *appsv1.Deployment + }{ + { + name: "valid container source with one container", + args: ContainerSourceArgs{ + Source: &v1alpha1.ContainerSource{ + ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: "test-namespace", UID: uid}, + Spec: v1alpha1.ContainerSourceSpec{ + Template: corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + ServiceAccountName: "test-service-account", + Containers: []corev1.Container{ + { + Name: "test-source", + 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", + }, + }, + }, + }, + ImagePullPolicy: corev1.PullIfNotPresent, + }, + }, + }, + }, + SourceSpec: duckv1.SourceSpec{ + Sink: duckv1.Destination{ + URI: apis.HTTP("test-sink"), + }, + }, + }, + }, + }, + want: &appsv1.Deployment{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "apps/v1", + Kind: "Deployment", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: fmt.Sprintf("containersource-%s-%s", name, uid), + Namespace: "test-namespace", + OwnerReferences: []metav1.OwnerReference{{ + APIVersion: "sources.knative.dev/v1alpha1", + Kind: "ContainerSource", + Name: name, + UID: uid, + Controller: &yes, + BlockOwnerDeletion: &yes, + }}, + Labels: map[string]string{ + "sources.knative.dev/containerSource": name, + "sources.knative.dev/source": "container-source-controller", + }, + }, + Spec: appsv1.DeploymentSpec{ + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "sources.knative.dev/containerSource": name, + "sources.knative.dev/source": "container-source-controller", + }, + }, + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{ + "sources.knative.dev/containerSource": name, + "sources.knative.dev/source": "container-source-controller", + }, + }, + Spec: corev1.PodSpec{ + ServiceAccountName: "test-service-account", + Containers: []corev1.Container{ + { + Name: "test-source", + 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", + }, + }, + }, { + Name: "K_SINK", + Value: "http://test-sink", + }, + { + Name: "K_CE_OVERRIDES", + Value: "", + }}, + ImagePullPolicy: corev1.PullIfNotPresent, + }, + }, + }, + }, + }, + }, + }, + + { + name: "valid container source with two containers", + args: ContainerSourceArgs{ + Source: &v1alpha1.ContainerSource{ + ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: "test-namespace", UID: uid}, + Spec: v1alpha1.ContainerSourceSpec{ + Template: corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + ServiceAccountName: "test-service-account", + Containers: []corev1.Container{ + { + 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", + }, + }, + }, + }, + ImagePullPolicy: corev1.PullIfNotPresent, + }, + { + Image: "test-image2", + Args: []string{"--test3=args3", "--test4=args4"}, + Env: []corev1.EnvVar{ + { + Name: "test3", + Value: "arg3", + }, + { + Name: "test4", + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + Key: "test4-secret", + }, + }, + }, + }, + }, + }, + }, + }, + SourceSpec: duckv1.SourceSpec{ + Sink: duckv1.Destination{ + URI: apis.HTTP("test-sink"), + }, + }, + }, + }, + }, + want: &appsv1.Deployment{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "apps/v1", + Kind: "Deployment", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: fmt.Sprintf("containersource-%s-%s", name, uid), + Namespace: "test-namespace", + OwnerReferences: []metav1.OwnerReference{{ + APIVersion: "sources.knative.dev/v1alpha1", + Kind: "ContainerSource", + Name: name, + UID: uid, + Controller: &yes, + BlockOwnerDeletion: &yes, + }}, + Labels: map[string]string{ + "sources.knative.dev/containerSource": name, + "sources.knative.dev/source": "container-source-controller", + }, + }, + Spec: appsv1.DeploymentSpec{ + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "sources.knative.dev/containerSource": name, + "sources.knative.dev/source": "container-source-controller", + }, + }, + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{ + "sources.knative.dev/containerSource": name, + "sources.knative.dev/source": "container-source-controller", + }, + }, + Spec: corev1.PodSpec{ + ServiceAccountName: "test-service-account", + Containers: []corev1.Container{ + { + 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", + }, + }, + }, { + Name: "K_SINK", + Value: "http://test-sink", + }, + { + Name: "K_CE_OVERRIDES", + Value: "", + }, + }, + ImagePullPolicy: corev1.PullIfNotPresent, + }, + { + Image: "test-image2", + Args: []string{ + "--test3=args3", + "--test4=args4", + }, + Env: []corev1.EnvVar{ + { + Name: "test3", + Value: "arg3", + }, + { + Name: "test4", + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + Key: "test4-secret", + }, + }, + }, + { + Name: "K_SINK", + Value: "http://test-sink", + }, + { + Name: "K_CE_OVERRIDES", + Value: "", + }, + }, + }, + }, + }, + }, + }, + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + test.args.Labels = Labels(name) + test.args.SinkURI = apis.HTTP("test-sink") + got := MakeDeployment(&test.args) + if diff := cmp.Diff(test.want, got); diff != "" { + t.Errorf("unexpected deploy (-want, +got) = %v", diff) + } + }) + } +} diff --git a/pkg/reconciler/containersource/resources/labels.go b/pkg/reconciler/containersource/resources/labels.go new file mode 100644 index 00000000000..6d0563a14ac --- /dev/null +++ b/pkg/reconciler/containersource/resources/labels.go @@ -0,0 +1,28 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package resources + +const ( + containerSourceController = "container-source-controller" +) + +func Labels(name string) map[string]string { + return map[string]string{ + "sources.knative.dev/source": containerSourceController, + "sources.knative.dev/containerSource": name, + } +} diff --git a/pkg/reconciler/testing/containersource.go b/pkg/reconciler/testing/containersource.go new file mode 100644 index 00000000000..bde6944363f --- /dev/null +++ b/pkg/reconciler/testing/containersource.go @@ -0,0 +1,123 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package testing + +import ( + "context" + "time" + + appsv1 "k8s.io/api/apps/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "knative.dev/pkg/apis" + + sourcesv1alpha1 "knative.dev/eventing/pkg/apis/sources/v1alpha1" +) + +// ContainerSourceOption enables further configuration of a ContainerSource. +type ContainerSourceOption func(*sourcesv1alpha1.ContainerSource) + +// NewContainerSource creates a ContainerSource with ContainerSourceOptions +func NewContainerSource(name, namespace string, o ...ContainerSourceOption) *sourcesv1alpha1.ContainerSource { + c := &sourcesv1alpha1.ContainerSource{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + }, + } + for _, opt := range o { + opt(c) + } + c.SetDefaults(context.Background()) + return c +} + +func WithContainerSourceUID(uid types.UID) ContainerSourceOption { + return func(s *sourcesv1alpha1.ContainerSource) { + s.UID = uid + } +} + +// WithInitContainerSourceConditions initializes the ContainerSource's conditions. +func WithInitContainerSourceConditions(s *sourcesv1alpha1.ContainerSource) { + s.Status.InitializeConditions() +} + +func WithContainerSourceSinkNotFound(msg string) ContainerSourceOption { + return func(s *sourcesv1alpha1.ContainerSource) { + s.Status.MarkNoSink("SinkNotFound", msg) + } +} + +func WithContainerSourceSinkMissing(msg string) ContainerSourceOption { + return func(s *sourcesv1alpha1.ContainerSource) { + s.Status.MarkNoSink("Missing", msg) + } +} + +func WithContainerSourceSink(uri *apis.URL) ContainerSourceOption { + return func(s *sourcesv1alpha1.ContainerSource) { + s.Status.MarkSink(uri) + } +} + +func WithContainerSourcePropagateDeploymentAvailability(d *appsv1.Deployment) ContainerSourceOption { + return func(s *sourcesv1alpha1.ContainerSource) { + s.Status.PropagateDeploymentAvailability(d) + } +} + +func WithContainerSourceDeployFailed(msg string) ContainerSourceOption { + return func(s *sourcesv1alpha1.ContainerSource) { + s.Status.MarkNotDeployed("DeploymentReconcileFailed", msg) + } +} + +func WithContainerSourceDeleted(c *sourcesv1alpha1.ContainerSource) { + t := metav1.NewTime(time.Unix(1e9, 0)) + c.ObjectMeta.SetDeletionTimestamp(&t) +} + +func WithContainerSourceSpec(spec sourcesv1alpha1.ContainerSourceSpec) ContainerSourceOption { + return func(c *sourcesv1alpha1.ContainerSource) { + c.Spec = spec + } +} + +func WithContainerSourceLabels(labels map[string]string) ContainerSourceOption { + return func(c *sourcesv1alpha1.ContainerSource) { + c.Labels = labels + } +} + +func WithContainerSourceAnnotations(annotations map[string]string) ContainerSourceOption { + return func(c *sourcesv1alpha1.ContainerSource) { + c.Annotations = annotations + } +} + +func WithContainerSourceStatusObservedGeneration(generation int64) ContainerSourceOption { + return func(c *sourcesv1alpha1.ContainerSource) { + c.Status.ObservedGeneration = generation + } +} + +func WithContainerSourceObjectMetaGeneration(generation int64) ContainerSourceOption { + return func(c *sourcesv1alpha1.ContainerSource) { + c.ObjectMeta.Generation = generation + } +} diff --git a/pkg/reconciler/testing/listers.go b/pkg/reconciler/testing/listers.go index 9d644929d86..be38f1ee95a 100644 --- a/pkg/reconciler/testing/listers.go +++ b/pkg/reconciler/testing/listers.go @@ -157,6 +157,10 @@ func (l *Listers) GetPingSourceLister() sourcelisters.PingSourceLister { return sourcelisters.NewPingSourceLister(l.indexerFor(&sourcesv1alpha1.PingSource{})) } +func (l *Listers) GetContainerSourceLister() sourcelisters.ContainerSourceLister { + return sourcelisters.NewContainerSourceLister(l.indexerFor(&sourcesv1alpha1.ContainerSource{})) +} + func (l *Listers) GetPingSourceV1alpha2Lister() sourcev1alpha2listers.PingSourceLister { return sourcev1alpha2listers.NewPingSourceLister(l.indexerFor(&sourcesv1alpha2.PingSource{})) } diff --git a/test/e2e/source_container_test.go b/test/e2e/source_container_test.go new file mode 100644 index 00000000000..bf167830f08 --- /dev/null +++ b/test/e2e/source_container_test.go @@ -0,0 +1,100 @@ +// +build e2e + +/* +Copyright 2020 The Knative Authors +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package e2e + +import ( + "fmt" + "testing" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/uuid" + + duckv1 "knative.dev/pkg/apis/duck/v1" + pkgTest "knative.dev/pkg/test" + + "knative.dev/eventing/test/lib" + "knative.dev/eventing/test/lib/resources" + + sourcesv1alpha1 "knative.dev/eventing/pkg/apis/sources/v1alpha1" + eventingtesting "knative.dev/eventing/pkg/reconciler/testing" +) + +func TestContainerSource(t *testing.T) { + const ( + containerSourceName = "e2e-container-source" + templateName = "e2e-container-source-template" + // the heartbeats image is built from test_images/heartbeats + imageName = "heartbeats" + + loggerPodName = "e2e-container-source-logger-pod" + ) + + client := setup(t, true) + defer tearDown(client) + + // create event logger pod and service + loggerPod := resources.EventLoggerPod(loggerPodName) + client.CreatePodOrFail(loggerPod, lib.WithService(loggerPodName)) + + // create container source + data := fmt.Sprintf("TestContainerSource%s", uuid.NewUUID()) + // args are the arguments passing to the container, msg is used in the heartbeats image + args := []string{"--msg=" + data} + // envVars are the environment variables of the container + envVars := []corev1.EnvVar{{ + Name: "POD_NAME", + Value: templateName, + }, { + Name: "POD_NAMESPACE", + Value: client.Namespace, + }} + containerSource := eventingtesting.NewContainerSource( + containerSourceName, + client.Namespace, + eventingtesting.WithContainerSourceSpec(sourcesv1alpha1.ContainerSourceSpec{ + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Name: templateName, + }, + Spec: corev1.PodSpec{ + Containers: []corev1.Container{{ + Name: imageName, + Image: pkgTest.ImagePath(imageName), + ImagePullPolicy: corev1.PullAlways, + Args: args, + Env: envVars, + }}, + }, + }, + SourceSpec: duckv1.SourceSpec{ + Sink: duckv1.Destination{Ref: resources.KnativeRefForService(loggerPodName, client.Namespace)}, + }, + }), + ) + client.CreateContainerSourceV1Alpha1OrFail(containerSource) + + // wait for all test resources to be ready + client.WaitForAllTestResourcesReadyOrFail() + + // verify the logger service receives the event + expectedCount := 2 + if err := client.CheckLog(loggerPodName, lib.CheckerContainsAtLeast(data, expectedCount)); err != nil { + t.Fatalf("String %q does not appear at least %d times in logs of logger pod %q: %v", data, expectedCount, loggerPodName, err) + } +} diff --git a/test/lib/creation.go b/test/lib/creation.go index 57612ad6895..f27ddac8b27 100644 --- a/test/lib/creation.go +++ b/test/lib/creation.go @@ -301,6 +301,17 @@ func (client *Client) CreateApiServerSourceOrFail(apiServerSource *sourcesv1alph client.Tracker.AddObj(apiServerSource) } +// CreateContainerSourceV1Alpha1OrFail will create a ContainerSource. +func (client *Client) CreateContainerSourceV1Alpha1OrFail(containerSource *sourcesv1alpha1.ContainerSource) { + client.T.Logf("Creating containersource %+v", containerSource) + containerInterface := client.Eventing.SourcesV1alpha1().ContainerSources(client.Namespace) + _, err := containerInterface.Create(containerSource) + if err != nil { + client.T.Fatalf("Failed to create containersource %q: %v", containerSource.Name, err) + } + client.Tracker.AddObj(containerSource) +} + // CreatePingSourceV1Alpha1OrFail will create an PingSource func (client *Client) CreatePingSourceV1Alpha1OrFail(pingSource *sourcesv1alpha1.PingSource) { client.T.Logf("Creating pingsource %+v", pingSource) From 4b58a56f018e362e05e9f093b54a07966c1924bf Mon Sep 17 00:00:00 2001 From: nachocano Date: Mon, 23 Mar 2020 17:46:02 -0700 Subject: [PATCH 02/16] remove omitempty --- pkg/apis/sources/v1alpha1/container_types.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/apis/sources/v1alpha1/container_types.go b/pkg/apis/sources/v1alpha1/container_types.go index 66e96856ec7..ce6fe9eabdf 100644 --- a/pkg/apis/sources/v1alpha1/container_types.go +++ b/pkg/apis/sources/v1alpha1/container_types.go @@ -57,7 +57,7 @@ type ContainerSourceSpec struct { duckv1.SourceSpec `json:",inline"` // Template describes the pods that will be created - Template corev1.PodTemplateSpec `json:"template,omitempty"` + Template corev1.PodTemplateSpec `json:"template"` } // GetGroupVersionKind returns the GroupVersionKind. From 34635cc785cd74767a7e636495012e290677def4 Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Mon, 23 Mar 2020 17:49:27 -0700 Subject: [PATCH 03/16] lint --- pkg/reconciler/containersource/resources/deployment_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/reconciler/containersource/resources/deployment_test.go b/pkg/reconciler/containersource/resources/deployment_test.go index 60b9f20036f..646755468e0 100644 --- a/pkg/reconciler/containersource/resources/deployment_test.go +++ b/pkg/reconciler/containersource/resources/deployment_test.go @@ -18,10 +18,10 @@ package resources import ( "fmt" - "knative.dev/pkg/apis" "testing" "knative.dev/eventing/pkg/apis/sources/v1alpha1" + "knative.dev/pkg/apis" "github.com/google/go-cmp/cmp" appsv1 "k8s.io/api/apps/v1" From 4e0b58e8507411c4b060c252de69a755d27b6487 Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Wed, 25 Mar 2020 16:08:48 -0700 Subject: [PATCH 04/16] using sinkbinding, all UTs broken --- .../sources/v1alpha1/container_lifecycle.go | 60 ++++---- .../containersource/containersource.go | 132 ++++++++---------- .../containersource/containersource_test.go | 10 +- pkg/reconciler/containersource/controller.go | 29 ++-- .../containersource/resources/deployment.go | 40 ++---- .../containersource/resources/sinkbinding.go | 55 ++++++++ pkg/reconciler/testing/listers.go | 4 + 7 files changed, 172 insertions(+), 158 deletions(-) create mode 100644 pkg/reconciler/containersource/resources/sinkbinding.go diff --git a/pkg/apis/sources/v1alpha1/container_lifecycle.go b/pkg/apis/sources/v1alpha1/container_lifecycle.go index 550911e8adc..d89171259d7 100644 --- a/pkg/apis/sources/v1alpha1/container_lifecycle.go +++ b/pkg/apis/sources/v1alpha1/container_lifecycle.go @@ -18,24 +18,25 @@ package v1alpha1 import ( appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" "knative.dev/eventing/pkg/apis/duck" "knative.dev/pkg/apis" ) const ( // ContainerSourceConditionReady has status True when the ContainerSource is ready to send events. - ContainerConditionReady = apis.ConditionReady + ContainerSourceConditionReady = apis.ConditionReady - // ContainerConditionSinkProvided has status True when the ContainerSource has been configured with a sink target. - ContainerConditionSinkProvided apis.ConditionType = "SinkProvided" + // ContainerSourceConditionSinkBindingReady has status True when the ContainerSource's SinkBinding is ready. + ContainerSourceConditionSinkBindingReady apis.ConditionType = "SinkBindingReady" - // ContainerConditionDeployed has status True when the ContainerSource has had it's deployment created. - ContainerConditionDeployed apis.ConditionType = "Deployed" + // ContainerSourceConditionReceiveAdapterReady has status True when the ContainerSource's ReceiveAdapter is ready. + ContainerSourceConditionReceiveAdapterReady apis.ConditionType = "ReceiveAdapterReady" ) var containerCondSet = apis.NewLivingConditionSet( - ContainerConditionSinkProvided, - ContainerConditionDeployed, + ContainerSourceConditionSinkBindingReady, + ContainerSourceConditionReceiveAdapterReady, ) // GetCondition returns the condition currently associated with the given type, or nil. @@ -53,34 +54,35 @@ func (s *ContainerSourceStatus) InitializeConditions() { containerCondSet.Manage(s).InitializeConditions() } -// MarkSink sets the condition that the source has a sink configured. -func (s *ContainerSourceStatus) MarkSink(uri *apis.URL) { - s.SinkURI = uri - if !uri.IsEmpty() { - containerCondSet.Manage(s).MarkTrue(ContainerConditionSinkProvided) - } else { - containerCondSet.Manage(s).MarkFalse(ContainerConditionSinkProvided, "SinkEmpty", "Sink has resolved to empty.%s", "") +// PropagateSinkBindingStatus uses the availability of the provided Deployment to determine if +// ContainerSourceConditionSinkBindingReady should be marked as true, false or unknown. +func (s *ContainerSourceStatus) PropagateSinkBindingStatus(status *SinkBindingStatus) { + // Do not copy conditions. + conditions := s.Conditions + s.SourceStatus = status.SourceStatus + s.Conditions = conditions + + cond := status.GetCondition(apis.ConditionReady) + switch { + case cond.Status == corev1.ConditionTrue: + containerCondSet.Manage(s).MarkTrue(ContainerSourceConditionSinkBindingReady) + case cond.Status == corev1.ConditionFalse: + containerCondSet.Manage(s).MarkFalse(ContainerSourceConditionSinkBindingReady, cond.Reason, cond.Message) + case cond.Status == corev1.ConditionUnknown: + containerCondSet.Manage(s).MarkUnknown(ContainerSourceConditionSinkBindingReady, cond.Reason, cond.Message) + default: + containerCondSet.Manage(s).MarkUnknown(ContainerSourceConditionSinkBindingReady, cond.Reason, cond.Message) } } -// 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...) -} - -// PropagateDeploymentAvailability uses the availability of the provided Deployment to determine if -// ContainerConditionDeployed should be marked as true or false. -func (s *ContainerSourceStatus) PropagateDeploymentAvailability(d *appsv1.Deployment) { +// PropagateReceiveAdapterStatus uses the availability of the provided Deployment to determine if +// ContainerSourceConditionReceiveAdapterReady should be marked as true or false. +func (s *ContainerSourceStatus) PropagateReceiveAdapterStatus(d *appsv1.Deployment) { if duck.DeploymentIsAvailable(&d.Status, false) { - containerCondSet.Manage(s).MarkTrue(ContainerConditionDeployed) + containerCondSet.Manage(s).MarkTrue(ContainerSourceConditionReceiveAdapterReady) } else { // I don't know how to propagate the status well, so just give the name of the Deployment // for now. - containerCondSet.Manage(s).MarkFalse(ContainerConditionDeployed, "DeploymentUnavailable", "The Deployment '%s' is unavailable.", d.Name) + containerCondSet.Manage(s).MarkFalse(ContainerSourceConditionReceiveAdapterReady, "DeploymentUnavailable", "The Deployment '%s' is unavailable.", d.Name) } } - -// 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/reconciler/containersource/containersource.go b/pkg/reconciler/containersource/containersource.go index 0db7ee69542..0db4e771f61 100644 --- a/pkg/reconciler/containersource/containersource.go +++ b/pkg/reconciler/containersource/containersource.go @@ -14,32 +14,26 @@ See the License for the specific language governing permissions and limitations under the License. */ -// Code generated by injection-gen. DO NOT EDIT. - package containersource import ( "context" - "encoding/json" "fmt" "go.uber.org/zap" - "k8s.io/apimachinery/pkg/api/equality" - apierrors "k8s.io/apimachinery/pkg/api/errors" - "knative.dev/eventing/pkg/logging" - "knative.dev/pkg/apis" - "knative.dev/pkg/resolver" - 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" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" appsv1listers "k8s.io/client-go/listers/apps/v1" "knative.dev/eventing/pkg/apis/sources/v1alpha1" + clientset "knative.dev/eventing/pkg/client/clientset/versioned" "knative.dev/eventing/pkg/client/injection/reconciler/sources/v1alpha1/containersource" listers "knative.dev/eventing/pkg/client/listers/sources/v1alpha1" + "knative.dev/eventing/pkg/logging" "knative.dev/eventing/pkg/reconciler/containersource/resources" - duckv1 "knative.dev/pkg/apis/duck/v1" pkgreconciler "knative.dev/pkg/reconciler" ) @@ -49,120 +43,104 @@ func newReconciledNormal(namespace, name string) pkgreconciler.Event { return pkgreconciler.NewEvent(corev1.EventTypeNormal, "ContainerSourceReconciled", "ContainerSource reconciled: \"%s/%s\"", namespace, name) } -func newWarningSinkNotFound(sink *duckv1.Destination) pkgreconciler.Event { - b, _ := json.Marshal(sink) - return pkgreconciler.NewEvent(corev1.EventTypeWarning, "SinkNotFound", "Sink not found: %s", string(b)) -} - // Reconciler implements controller.Reconciler for ContainerSource resources. type Reconciler struct { - kubeClientSet kubernetes.Interface + kubeClientSet kubernetes.Interface + eventingClientSet clientset.Interface // listers index properties about resources containerSourceLister listers.ContainerSourceLister + sinkBindingLister listers.SinkBindingLister deploymentLister appsv1listers.DeploymentLister - - sinkResolver *resolver.URIResolver } // Check that our Reconciler implements Interface var _ containersource.Interface = (*Reconciler)(nil) -// Optionally check that our Reconciler implements Finalizer -//var _ containersource.Finalizer = (*Reconciler)(nil) - // ReconcileKind implements Interface.ReconcileKind. func (r *Reconciler) ReconcileKind(ctx context.Context, source *v1alpha1.ContainerSource) pkgreconciler.Event { source.Status.InitializeConditions() source.Status.ObservedGeneration = source.Generation - dest := source.Spec.Sink.DeepCopy() - if dest.Ref != nil { - // To call URIFromDestinationV1(), dest.Ref must have a Namespace. If there is - // no Namespace defined in dest.Ref, we will use the Namespace of the source - // as the Namespace of dest.Ref. - if dest.Ref.Namespace == "" { - dest.Ref.Namespace = source.GetNamespace() - } - } - - sinkURI, err := r.sinkResolver.URIFromDestinationV1(*dest, source) + _, err := r.reconcileSinkBinding(ctx, source) if err != nil { - source.Status.MarkNoSink("SinkNotFound", "") - return newWarningSinkNotFound(dest) + logging.FromContext(ctx).Error("Error reconciling SinkBinding", zap.Error(err)) + return err } - source.Status.MarkSink(sinkURI) - ra, err := r.reconcileReceiveAdapter(ctx, source, sinkURI) + _, err = r.reconcileReceiveAdapter(ctx, source) if err != nil { - source.Status.MarkNotDeployed("DeploymentReconcileFailed", "Failed to reconcile deployment: %v", err) + logging.FromContext(ctx).Error("Error reconciling ReceiveAdapter", zap.Error(err)) return err } - source.Status.PropagateDeploymentAvailability(ra) + return newReconciledNormal(source.Namespace, source.Name) } -func (r *Reconciler) reconcileReceiveAdapter(ctx context.Context, source *v1alpha1.ContainerSource, sinkURI *apis.URL) (*appsv1.Deployment, error) { +func (r *Reconciler) reconcileReceiveAdapter(ctx context.Context, source *v1alpha1.ContainerSource) (*appsv1.Deployment, error) { - ceOverrides := r.marshalCeOverrides(ctx, source) - args := &resources.ContainerSourceArgs{ - Source: source, - SinkURI: sinkURI, - CeOverrides: ceOverrides, - Labels: resources.Labels(source.Name), - } - expected := resources.MakeDeployment(args) + expected := resources.MakeDeployment(source) ra, err := r.deploymentLister.Deployments(expected.Namespace).Get(expected.Name) if apierrors.IsNotFound(err) { ra, err = r.kubeClientSet.AppsV1().Deployments(expected.Namespace).Create(expected) if err != nil { - return nil, fmt.Errorf("creating new deployment: %v", err) + return nil, fmt.Errorf("creating new Deployment: %v", err) } return ra, nil } else if err != nil { - return nil, fmt.Errorf("getting deployment: %v", err) + return nil, fmt.Errorf("getting Deployment: %v", err) } else if !metav1.IsControlledBy(ra, source) { - return nil, fmt.Errorf("deployment %q is not owned by ContainerSource %q", ra.Name, source.Name) - } else if r.podSpecChanged(ra.Spec.Template.Spec, expected.Spec.Template.Spec) { + return nil, fmt.Errorf("Deployment %q is not owned by ContainerSource %q", ra.Name, source.Name) + } else if r.podSpecChanged(&ra.Spec.Template.Spec, &expected.Spec.Template.Spec) { ra.Spec.Template.Spec = expected.Spec.Template.Spec ra, err = r.kubeClientSet.AppsV1().Deployments(expected.Namespace).Update(ra) if err != nil { - return ra, fmt.Errorf("updating deployment: %v", err) + return nil, fmt.Errorf("updating Deployment: %v", err) } return ra, nil } else { - logging.FromContext(ctx).Debug("Reusing existing receive adapter", zap.Any("receiveAdapter", ra)) + logging.FromContext(ctx).Debug("Reusing existing Deployment", zap.Any("Deployment", ra)) } + + source.Status.PropagateReceiveAdapterStatus(ra) return ra, nil } -func (r *Reconciler) podSpecChanged(oldPodSpec corev1.PodSpec, newPodSpec corev1.PodSpec) bool { - // 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 newPodSpec. - 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 +func (r *Reconciler) reconcileSinkBinding(ctx context.Context, src *v1alpha1.ContainerSource) (*v1alpha1.SinkBinding, error) { + + expected := resources.MakeSinkBinding(src) + + sb, err := r.sinkBindingLister.SinkBindings(src.Namespace).Get(expected.Name) + if apierrors.IsNotFound(err) { + sb, err = r.eventingClientSet.SourcesV1alpha1().SinkBindings(src.Namespace).Create(expected) + if err != nil { + return nil, fmt.Errorf("creating new SinkBinding: %v", err) } + return sb, err + } else if err != nil { + return nil, fmt.Errorf("getting SinkBinding: %v", err) + } else if !metav1.IsControlledBy(sb, src) { + return nil, fmt.Errorf("SinkBinding %q is not owned by ContainerSource %q", sb.Name, src.Name) + } else if r.sinkBindingSpecChanged(&sb.Spec, &expected.Spec) { + sb.Spec = expected.Spec + sb, err = r.eventingClientSet.SourcesV1alpha1().SinkBindings(src.Namespace).Update(sb) + if err != nil { + return nil, fmt.Errorf("updating SinkBinding: %v", err) + } + return sb, nil + } else { + logging.FromContext(ctx).Debug("Reusing existing SinkBinding", zap.Any("SinkBinding", sb)) } - return false + + src.Status.PropagateSinkBindingStatus(&sb.Status) + return sb, nil } -func (r *Reconciler) marshalCeOverrides(ctx context.Context, source *v1alpha1.ContainerSource) string { - var ceOverrides string - if source.Spec.CloudEventOverrides != nil { - if co, err := json.Marshal(source.Spec.CloudEventOverrides); err != nil { - logging.FromContext(ctx).Error("Failed to marshal CloudEventOverrides into JSON", zap.Any("source", source), zap.Error(err)) - } else if len(co) > 0 { - ceOverrides = string(co) - } - } - return ceOverrides +func (r *Reconciler) podSpecChanged(have *corev1.PodSpec, want *corev1.PodSpec) bool { + return !equality.Semantic.DeepDerivative(want, have) +} + +func (r *Reconciler) sinkBindingSpecChanged(have *v1alpha1.SinkBindingSpec, want *v1alpha1.SinkBindingSpec) bool { + return !equality.Semantic.DeepDerivative(want, have) } diff --git a/pkg/reconciler/containersource/containersource_test.go b/pkg/reconciler/containersource/containersource_test.go index cbb9c983003..5b050bc0fa4 100644 --- a/pkg/reconciler/containersource/containersource_test.go +++ b/pkg/reconciler/containersource/containersource_test.go @@ -21,19 +21,16 @@ import ( "fmt" "testing" - "knative.dev/pkg/apis" - "knative.dev/pkg/logging" - "knative.dev/pkg/resolver" - appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/kubernetes/scheme" clientgotesting "k8s.io/client-go/testing" fakeeventingclient "knative.dev/eventing/pkg/client/injection/client/fake" + "knative.dev/pkg/apis" fakekubeclient "knative.dev/pkg/client/injection/kube/client/fake" + "knative.dev/pkg/logging" "knative.dev/eventing/pkg/client/injection/reconciler/sources/v1alpha1/containersource" "knative.dev/eventing/pkg/reconciler/containersource/resources" @@ -323,9 +320,10 @@ func TestAllCases(t *testing.T) { ctx = addressable.WithDuck(ctx) r := &Reconciler{ kubeClientSet: fakekubeclient.Get(ctx), + eventingClientSet: fakeeventingclient.Get(ctx), containerSourceLister: listers.GetContainerSourceLister(), deploymentLister: listers.GetDeploymentLister(), - sinkResolver: resolver.NewURIResolver(ctx, func(types.NamespacedName) {}), + sinkBindingLister: listers.GetSinkBindingLister(), } return containersource.NewReconciler(ctx, logging.FromContext(ctx), fakeeventingclient.Get(ctx), listers.GetContainerSourceLister(), controller.GetEventRecorder(ctx), r) }, diff --git a/pkg/reconciler/containersource/controller.go b/pkg/reconciler/containersource/controller.go index 01ae9e0b970..1526465aa93 100644 --- a/pkg/reconciler/containersource/controller.go +++ b/pkg/reconciler/containersource/controller.go @@ -14,30 +14,22 @@ See the License for the specific language governing permissions and limitations under the License. */ -// Code generated by injection-gen. DO NOT EDIT. - package containersource import ( "context" "k8s.io/client-go/tools/cache" - "knative.dev/pkg/logging" - "knative.dev/pkg/resolver" - "knative.dev/eventing/pkg/apis/sources/v1alpha1" - "knative.dev/eventing/pkg/client/injection/informers/sources/v1alpha1/containersource" + eventingclient "knative.dev/eventing/pkg/client/injection/client" + containersourceinformer "knative.dev/eventing/pkg/client/injection/informers/sources/v1alpha1/containersource" + sinkbindinginformer "knative.dev/eventing/pkg/client/injection/informers/sources/v1alpha1/sinkbinding" v1alpha1containersource "knative.dev/eventing/pkg/client/injection/reconciler/sources/v1alpha1/containersource" kubeclient "knative.dev/pkg/client/injection/kube/client" deploymentinformer "knative.dev/pkg/client/injection/kube/informers/apps/v1/deployment" "knative.dev/pkg/configmap" "knative.dev/pkg/controller" -) - -const ( - // controllerAgentName is the string used by this controller to identify - // itself when creating events. - controllerAgentName = "container-source-controller" + "knative.dev/pkg/logging" ) // NewController creates a Reconciler for ContainerSource and returns the result of NewImpl. @@ -47,17 +39,19 @@ func NewController( ) *controller.Impl { kubeClient := kubeclient.Get(ctx) - - containersourceInformer := containersource.Get(ctx) + eventingClient := eventingclient.Get(ctx) + containersourceInformer := containersourceinformer.Get(ctx) + sinkbindingInformer := sinkbindinginformer.Get(ctx) deploymentInformer := deploymentinformer.Get(ctx) r := &Reconciler{ kubeClientSet: kubeClient, + eventingClientSet: eventingClient, containerSourceLister: containersourceInformer.Lister(), deploymentLister: deploymentInformer.Lister(), + sinkBindingLister: sinkbindingInformer.Lister(), } impl := v1alpha1containersource.NewImpl(ctx, r) - r.sinkResolver = resolver.NewURIResolver(ctx, impl.EnqueueKey) logging.FromContext(ctx).Info("Setting up event handlers.") containersourceInformer.Informer().AddEventHandler(controller.HandleAll(impl.Enqueue)) @@ -67,5 +61,10 @@ func NewController( Handler: controller.HandleAll(impl.EnqueueControllerOf), }) + sinkbindingInformer.Informer().AddEventHandler(cache.FilteringResourceEventHandler{ + FilterFunc: controller.FilterGroupKind(v1alpha1.Kind("ContainerSource")), + Handler: controller.HandleAll(impl.EnqueueControllerOf), + }) + return impl } diff --git a/pkg/reconciler/containersource/resources/deployment.go b/pkg/reconciler/containersource/resources/deployment.go index 524ca2648f9..fb873bf1789 100644 --- a/pkg/reconciler/containersource/resources/deployment.go +++ b/pkg/reconciler/containersource/resources/deployment.go @@ -17,42 +17,20 @@ limitations under the License. package resources import ( - "fmt" - appsv1 "k8s.io/api/apps/v1" - corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "knative.dev/eventing/pkg/apis/sources/v1alpha1" - "knative.dev/pkg/apis" "knative.dev/pkg/kmeta" ) -type ContainerSourceArgs struct { - Source *v1alpha1.ContainerSource - SinkURI *apis.URL - CeOverrides string - Labels map[string]string -} - -func MakeDeployment(args *ContainerSourceArgs) *appsv1.Deployment { - template := args.Source.Spec.Template - - for i := range template.Spec.Containers { - template.Spec.Containers[i].Env = append(template.Spec.Containers[i].Env, corev1.EnvVar{ - Name: "K_SINK", - Value: args.SinkURI.String(), - }) - template.Spec.Containers[i].Env = append(template.Spec.Containers[i].Env, corev1.EnvVar{ - Name: "K_CE_OVERRIDES", - Value: args.CeOverrides, - }) - } - +func MakeDeployment(source *v1alpha1.ContainerSource) *appsv1.Deployment { + template := source.Spec.Template if template.Labels == nil { template.Labels = make(map[string]string) } - for k, v := range args.Labels { + labels := Labels(source.Name) + for k, v := range labels { template.Labels[k] = v } @@ -62,16 +40,16 @@ func MakeDeployment(args *ContainerSourceArgs) *appsv1.Deployment { Kind: "Deployment", }, ObjectMeta: metav1.ObjectMeta{ - Name: kmeta.ChildName(fmt.Sprintf("containersource-%s-", args.Source.Name), string(args.Source.UID)), - Namespace: args.Source.Namespace, + Name: kmeta.ChildName(source.Name, "-containersource" /*suffix*/), + Namespace: source.Namespace, OwnerReferences: []metav1.OwnerReference{ - *kmeta.NewControllerRef(args.Source), + *kmeta.NewControllerRef(source), }, - Labels: args.Labels, + Labels: labels, }, Spec: appsv1.DeploymentSpec{ Selector: &metav1.LabelSelector{ - MatchLabels: args.Labels, + MatchLabels: labels, }, Template: template, }, diff --git a/pkg/reconciler/containersource/resources/sinkbinding.go b/pkg/reconciler/containersource/resources/sinkbinding.go new file mode 100644 index 00000000000..b9812867447 --- /dev/null +++ b/pkg/reconciler/containersource/resources/sinkbinding.go @@ -0,0 +1,55 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package resources + +import ( + appsv1 "k8s.io/api/apps/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "knative.dev/eventing/pkg/apis/sources/v1alpha1" + duckv1alpha1 "knative.dev/pkg/apis/duck/v1alpha1" + "knative.dev/pkg/kmeta" + "knative.dev/pkg/tracker" +) + +var subjectGVK = appsv1.SchemeGroupVersion.WithKind("Deployment") + +func MakeSinkBinding(source *v1alpha1.ContainerSource) *v1alpha1.SinkBinding { + subjectAPIVersion, subjectKind := subjectGVK.ToAPIVersionAndKind() + + sb := &v1alpha1.SinkBinding{ + ObjectMeta: metav1.ObjectMeta{ + OwnerReferences: []metav1.OwnerReference{ + *kmeta.NewControllerRef(source), + }, + Name: kmeta.ChildName(source.Name, "-containersource" /*suffix*/), + Namespace: source.Namespace, + }, + Spec: v1alpha1.SinkBindingSpec{ + SourceSpec: source.Spec.SourceSpec, + BindingSpec: duckv1alpha1.BindingSpec{ + Subject: tracker.Reference{ + APIVersion: subjectAPIVersion, + Kind: subjectKind, + Selector: &metav1.LabelSelector{ + MatchLabels: Labels(source.Name), + }, + }, + }, + }, + } + return sb +} diff --git a/pkg/reconciler/testing/listers.go b/pkg/reconciler/testing/listers.go index db6cb22b177..b50771b6b33 100644 --- a/pkg/reconciler/testing/listers.go +++ b/pkg/reconciler/testing/listers.go @@ -168,6 +168,10 @@ func (l *Listers) GetContainerSourceLister() sourcelisters.ContainerSourceLister return sourcelisters.NewContainerSourceLister(l.indexerFor(&sourcesv1alpha1.ContainerSource{})) } +func (l *Listers) GetSinkBindingLister() sourcelisters.SinkBindingLister { + return sourcelisters.NewSinkBindingLister(l.indexerFor(&sourcesv1alpha1.SinkBinding{})) +} + func (l *Listers) GetPingSourceV1alpha2Lister() sourcev1alpha2listers.PingSourceLister { return sourcev1alpha2listers.NewPingSourceLister(l.indexerFor(&sourcesv1alpha2.PingSource{})) } From 9ce16dfeb3c7d32d12345d6d2a46ab106707ade6 Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Wed, 25 Mar 2020 21:12:50 -0700 Subject: [PATCH 05/16] fixing some UTs --- .../v1alpha1/container_lifecycle_test.go | 183 ++++++++---------- .../resources/deployment_test.go | 171 +++++++--------- .../resources/sinkbinding_test.go | 106 ++++++++++ pkg/reconciler/testing/containersource.go | 28 +-- 4 files changed, 267 insertions(+), 221 deletions(-) create mode 100644 pkg/reconciler/containersource/resources/sinkbinding_test.go diff --git a/pkg/apis/sources/v1alpha1/container_lifecycle_test.go b/pkg/apis/sources/v1alpha1/container_lifecycle_test.go index 4c21c250eb5..8b96039d8d3 100644 --- a/pkg/apis/sources/v1alpha1/container_lifecycle_test.go +++ b/pkg/apis/sources/v1alpha1/container_lifecycle_test.go @@ -26,6 +26,7 @@ import ( corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" ) var ( @@ -53,6 +54,34 @@ var ( }, }, } + + readySinkBinding = &SinkBinding{ + Status: SinkBindingStatus{ + SourceStatus: duckv1.SourceStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: apis.ConditionReady, + Status: corev1.ConditionTrue, + }}, + }, + }, + }, + } + + notReadySinkBinding = &SinkBinding{ + Status: SinkBindingStatus{ + SourceStatus: duckv1.SourceStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: apis.ConditionReady, + Status: corev1.ConditionFalse, + Reason: "Testing", + Message: "hi", + }}, + }, + }, + }, + } ) func TestContainerSourceStatusIsReady(t *testing.T) { @@ -73,83 +102,73 @@ func TestContainerSourceStatusIsReady(t *testing.T) { }(), want: false, }, { - name: "mark deployed", + name: "mark ready ra", s: func() *ContainerSourceStatus { s := &ContainerSourceStatus{} s.InitializeConditions() - s.PropagateDeploymentAvailability(availDeployment) + s.PropagateReceiveAdapterStatus(availDeployment) return s }(), want: false, }, { - name: "mark sink", + name: "mark ready sb", s: func() *ContainerSourceStatus { s := &ContainerSourceStatus{} s.InitializeConditions() - s.MarkSink(apis.HTTP("example")) + s.PropagateSinkBindingStatus(&readySinkBinding.Status) return s }(), want: false, }, { - name: "mark sink and deployed", + name: "mark ready sb and ra", s: func() *ContainerSourceStatus { s := &ContainerSourceStatus{} s.InitializeConditions() - s.MarkSink(apis.HTTP("example")) - s.PropagateDeploymentAvailability(availDeployment) + s.PropagateSinkBindingStatus(&readySinkBinding.Status) + s.PropagateReceiveAdapterStatus(availDeployment) return s }(), want: true, }, { - name: "mark sink and deployed then no sink", + name: "mark ready sb and ra the no sb", s: func() *ContainerSourceStatus { s := &ContainerSourceStatus{} s.InitializeConditions() - s.MarkSink(apis.HTTP("example")) - s.PropagateDeploymentAvailability(availDeployment) - s.MarkNoSink("Testing", "") + s.PropagateSinkBindingStatus(&readySinkBinding.Status) + s.PropagateReceiveAdapterStatus(availDeployment) + s.PropagateSinkBindingStatus(¬ReadySinkBinding.Status) return s }(), want: false, }, { - name: "mark sink and deployed then not deployed", + name: "mark ready sb and ra then not ra", s: func() *ContainerSourceStatus { s := &ContainerSourceStatus{} s.InitializeConditions() - s.MarkSink(apis.HTTP("example")) - s.PropagateDeploymentAvailability(availDeployment) - s.PropagateDeploymentAvailability(unavailDeployment) + s.PropagateReceiveAdapterStatus(availDeployment) + s.PropagateSinkBindingStatus(¬ReadySinkBinding.Status) + s.PropagateReceiveAdapterStatus(unavailDeployment) return s }(), want: false, }, { - name: "mark sink nil and deployed", + name: "mark not ready sb and ready ra", s: func() *ContainerSourceStatus { s := &ContainerSourceStatus{} s.InitializeConditions() - s.MarkSink(nil) - s.PropagateDeploymentAvailability(availDeployment) + s.PropagateSinkBindingStatus(¬ReadySinkBinding.Status) + s.PropagateReceiveAdapterStatus(availDeployment) return s }(), want: false, }, { - name: "mark sink empty and deployed", + name: "mark not ready sb and ra then ready sb", s: func() *ContainerSourceStatus { s := &ContainerSourceStatus{} s.InitializeConditions() - s.MarkSink(&apis.URL{}) - s.PropagateDeploymentAvailability(availDeployment) - return s - }(), - want: false, - }, { - name: "mark sink nil and deployed then sink", - s: func() *ContainerSourceStatus { - s := &ContainerSourceStatus{} - s.InitializeConditions() - s.MarkSink(nil) - s.PropagateDeploymentAvailability(availDeployment) - s.MarkSink(apis.HTTP("example")) + s.PropagateSinkBindingStatus(¬ReadySinkBinding.Status) + s.PropagateReceiveAdapterStatus(availDeployment) + s.PropagateSinkBindingStatus(&readySinkBinding.Status) return s }(), want: true, @@ -174,7 +193,7 @@ func TestContainerSourceStatusGetCondition(t *testing.T) { }{{ name: "uninitialized", s: &ContainerSourceStatus{}, - condQuery: ContainerConditionReady, + condQuery: ContainerSourceConditionReady, want: nil, }, { name: "initialized", @@ -183,130 +202,98 @@ func TestContainerSourceStatusGetCondition(t *testing.T) { s.InitializeConditions() return s }(), - condQuery: ContainerConditionReady, + condQuery: ContainerSourceConditionReady, want: &apis.Condition{ - Type: ContainerConditionReady, + Type: ContainerSourceConditionReady, Status: corev1.ConditionUnknown, }, }, { - name: "mark deployed", + name: "mark ready ra", s: func() *ContainerSourceStatus { s := &ContainerSourceStatus{} s.InitializeConditions() - s.PropagateDeploymentAvailability(availDeployment) + s.PropagateReceiveAdapterStatus(availDeployment) return s }(), - condQuery: ContainerConditionReady, + condQuery: ContainerSourceConditionReady, want: &apis.Condition{ - Type: ContainerConditionReady, + Type: ContainerSourceConditionReady, Status: corev1.ConditionUnknown, }, }, { - name: "mark sink", + name: "mark ready sb", s: func() *ContainerSourceStatus { s := &ContainerSourceStatus{} s.InitializeConditions() - s.MarkSink(apis.HTTP("example")) + s.PropagateSinkBindingStatus(&readySinkBinding.Status) return s }(), - condQuery: ContainerConditionReady, + condQuery: ContainerSourceConditionReady, want: &apis.Condition{ - Type: ContainerConditionReady, + Type: ContainerSourceConditionReady, Status: corev1.ConditionUnknown, }, }, { - name: "mark sink and deployed", + name: "mark ready sb and ra", s: func() *ContainerSourceStatus { s := &ContainerSourceStatus{} s.InitializeConditions() - s.MarkSink(apis.HTTP("example")) - s.PropagateDeploymentAvailability(availDeployment) + s.PropagateSinkBindingStatus(&readySinkBinding.Status) + s.PropagateReceiveAdapterStatus(availDeployment) return s }(), - condQuery: ContainerConditionReady, + condQuery: ContainerSourceConditionReady, want: &apis.Condition{ - Type: ContainerConditionReady, + Type: ContainerSourceConditionReady, Status: corev1.ConditionTrue, }, }, { - name: "mark sink and deployed then no sink", + name: "mark ready sb and ra then no sb", s: func() *ContainerSourceStatus { s := &ContainerSourceStatus{} s.InitializeConditions() - s.MarkSink(apis.HTTP("example")) - s.PropagateDeploymentAvailability(availDeployment) - s.MarkNoSink("Testing", "hi%s", "") + s.PropagateSinkBindingStatus(&readySinkBinding.Status) + s.PropagateReceiveAdapterStatus(availDeployment) + s.PropagateSinkBindingStatus(¬ReadySinkBinding.Status) return s }(), - condQuery: ContainerConditionReady, + condQuery: ContainerSourceConditionReady, want: &apis.Condition{ - Type: ContainerConditionReady, + Type: ContainerSourceConditionReady, Status: corev1.ConditionFalse, Reason: "Testing", Message: "hi", }, }, { - name: "mark sink and deployed then not deployed", + name: "mark ready sb and ra then no ra", s: func() *ContainerSourceStatus { s := &ContainerSourceStatus{} s.InitializeConditions() - s.MarkSink(apis.HTTP("example")) - s.PropagateDeploymentAvailability(availDeployment) - s.PropagateDeploymentAvailability(unavailDeployment) + s.PropagateSinkBindingStatus(&readySinkBinding.Status) + s.PropagateReceiveAdapterStatus(availDeployment) + s.PropagateReceiveAdapterStatus(unavailDeployment) return s }(), - condQuery: ContainerConditionReady, + condQuery: ContainerSourceConditionReady, want: &apis.Condition{ - Type: ContainerConditionReady, + Type: ContainerSourceConditionReady, Status: corev1.ConditionFalse, Reason: "DeploymentUnavailable", Message: "The Deployment 'test-name' is unavailable.", }, }, { - name: "mark sink nil and deployed", - s: func() *ContainerSourceStatus { - s := &ContainerSourceStatus{} - s.InitializeConditions() - s.MarkSink(nil) - s.PropagateDeploymentAvailability(availDeployment) - return s - }(), - condQuery: ContainerConditionReady, - want: &apis.Condition{ - Type: ContainerConditionReady, - Status: corev1.ConditionFalse, - Reason: "SinkEmpty", - Message: "Sink has resolved to empty.", - }, - }, { - name: "mark sink empty and deployed", - s: func() *ContainerSourceStatus { - s := &ContainerSourceStatus{} - s.InitializeConditions() - s.MarkSink(&apis.URL{}) - s.PropagateDeploymentAvailability(availDeployment) - return s - }(), - condQuery: ContainerConditionReady, - want: &apis.Condition{ - Type: ContainerConditionReady, - Status: corev1.ConditionFalse, - Reason: "SinkEmpty", - Message: "Sink has resolved to empty.", - }, - }, { - name: "mark sink nil and deployed then sink", + name: "mark not ready sb and ready ra then ready sb", s: func() *ContainerSourceStatus { s := &ContainerSourceStatus{} s.InitializeConditions() - s.MarkSink(nil) - s.PropagateDeploymentAvailability(availDeployment) - s.MarkSink(apis.HTTP("example")) + s.PropagateSinkBindingStatus(¬ReadySinkBinding.Status) + s.PropagateReceiveAdapterStatus(availDeployment) + s.PropagateSinkBindingStatus(&readySinkBinding.Status) return s }(), - condQuery: ContainerConditionReady, + condQuery: ContainerSourceConditionReady, want: &apis.Condition{ - Type: ContainerConditionReady, + Type: ContainerSourceConditionReady, Status: corev1.ConditionTrue, }, }} diff --git a/pkg/reconciler/containersource/resources/deployment_test.go b/pkg/reconciler/containersource/resources/deployment_test.go index 646755468e0..ea1c001e5e5 100644 --- a/pkg/reconciler/containersource/resources/deployment_test.go +++ b/pkg/reconciler/containersource/resources/deployment_test.go @@ -38,47 +38,45 @@ const ( func TestMakeDeployment(t *testing.T) { yes := true tests := []struct { - name string - args ContainerSourceArgs - want *appsv1.Deployment + name string + source *v1alpha1.ContainerSource + want *appsv1.Deployment }{ { name: "valid container source with one container", - args: ContainerSourceArgs{ - Source: &v1alpha1.ContainerSource{ - ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: "test-namespace", UID: uid}, - Spec: v1alpha1.ContainerSourceSpec{ - Template: corev1.PodTemplateSpec{ - Spec: corev1.PodSpec{ - ServiceAccountName: "test-service-account", - Containers: []corev1.Container{ - { - Name: "test-source", - 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", - }, + source: &v1alpha1.ContainerSource{ + ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: "test-namespace", UID: uid}, + Spec: v1alpha1.ContainerSourceSpec{ + Template: corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + ServiceAccountName: "test-service-account", + Containers: []corev1.Container{ + { + Name: "test-source", + 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", }, }, }, - ImagePullPolicy: corev1.PullIfNotPresent, }, + ImagePullPolicy: corev1.PullIfNotPresent, }, }, }, - SourceSpec: duckv1.SourceSpec{ - Sink: duckv1.Destination{ - URI: apis.HTTP("test-sink"), - }, + }, + SourceSpec: duckv1.SourceSpec{ + Sink: duckv1.Destination{ + URI: apis.HTTP("test-sink"), }, }, }, @@ -89,7 +87,7 @@ func TestMakeDeployment(t *testing.T) { Kind: "Deployment", }, ObjectMeta: metav1.ObjectMeta{ - Name: fmt.Sprintf("containersource-%s-%s", name, uid), + Name: fmt.Sprintf("%s-containersource", name), Namespace: "test-namespace", OwnerReferences: []metav1.OwnerReference{{ APIVersion: "sources.knative.dev/v1alpha1", @@ -139,13 +137,6 @@ func TestMakeDeployment(t *testing.T) { Key: "test2-secret", }, }, - }, { - Name: "K_SINK", - Value: "http://test-sink", - }, - { - Name: "K_CE_OVERRIDES", - Value: "", }}, ImagePullPolicy: corev1.PullIfNotPresent, }, @@ -158,47 +149,45 @@ func TestMakeDeployment(t *testing.T) { { name: "valid container source with two containers", - args: ContainerSourceArgs{ - Source: &v1alpha1.ContainerSource{ - ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: "test-namespace", UID: uid}, - Spec: v1alpha1.ContainerSourceSpec{ - Template: corev1.PodTemplateSpec{ - Spec: corev1.PodSpec{ - ServiceAccountName: "test-service-account", - Containers: []corev1.Container{ - { - 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", - }, + source: &v1alpha1.ContainerSource{ + ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: "test-namespace", UID: uid}, + Spec: v1alpha1.ContainerSourceSpec{ + Template: corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + ServiceAccountName: "test-service-account", + Containers: []corev1.Container{ + { + 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", }, }, }, - ImagePullPolicy: corev1.PullIfNotPresent, }, - { - Image: "test-image2", - Args: []string{"--test3=args3", "--test4=args4"}, - Env: []corev1.EnvVar{ - { - Name: "test3", - Value: "arg3", - }, - { - Name: "test4", - ValueFrom: &corev1.EnvVarSource{ - SecretKeyRef: &corev1.SecretKeySelector{ - Key: "test4-secret", - }, + ImagePullPolicy: corev1.PullIfNotPresent, + }, + { + Image: "test-image2", + Args: []string{"--test3=args3", "--test4=args4"}, + Env: []corev1.EnvVar{ + { + Name: "test3", + Value: "arg3", + }, + { + Name: "test4", + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + Key: "test4-secret", }, }, }, @@ -206,10 +195,10 @@ func TestMakeDeployment(t *testing.T) { }, }, }, - SourceSpec: duckv1.SourceSpec{ - Sink: duckv1.Destination{ - URI: apis.HTTP("test-sink"), - }, + }, + SourceSpec: duckv1.SourceSpec{ + Sink: duckv1.Destination{ + URI: apis.HTTP("test-sink"), }, }, }, @@ -220,7 +209,7 @@ func TestMakeDeployment(t *testing.T) { Kind: "Deployment", }, ObjectMeta: metav1.ObjectMeta{ - Name: fmt.Sprintf("containersource-%s-%s", name, uid), + Name: fmt.Sprintf("%s-containersource", name), Namespace: "test-namespace", OwnerReferences: []metav1.OwnerReference{{ APIVersion: "sources.knative.dev/v1alpha1", @@ -269,13 +258,6 @@ func TestMakeDeployment(t *testing.T) { Key: "test2-secret", }, }, - }, { - Name: "K_SINK", - Value: "http://test-sink", - }, - { - Name: "K_CE_OVERRIDES", - Value: "", }, }, ImagePullPolicy: corev1.PullIfNotPresent, @@ -299,14 +281,6 @@ func TestMakeDeployment(t *testing.T) { }, }, }, - { - Name: "K_SINK", - Value: "http://test-sink", - }, - { - Name: "K_CE_OVERRIDES", - Value: "", - }, }, }, }, @@ -319,9 +293,8 @@ func TestMakeDeployment(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { - test.args.Labels = Labels(name) - test.args.SinkURI = apis.HTTP("test-sink") - got := MakeDeployment(&test.args) + test.source.Labels = Labels(name) + got := MakeDeployment(test.source) if diff := cmp.Diff(test.want, got); diff != "" { t.Errorf("unexpected deploy (-want, +got) = %v", diff) } diff --git a/pkg/reconciler/containersource/resources/sinkbinding_test.go b/pkg/reconciler/containersource/resources/sinkbinding_test.go new file mode 100644 index 00000000000..4971593c239 --- /dev/null +++ b/pkg/reconciler/containersource/resources/sinkbinding_test.go @@ -0,0 +1,106 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package resources + +import ( + "fmt" + "testing" + + "knative.dev/eventing/pkg/apis/sources/v1alpha1" + "knative.dev/pkg/apis" + duckv1alpha1 "knative.dev/pkg/apis/duck/v1alpha1" + "knative.dev/pkg/kmeta" + "knative.dev/pkg/tracker" + + "github.com/google/go-cmp/cmp" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + duckv1 "knative.dev/pkg/apis/duck/v1" +) + +const ( + containerSourceName = "test-name" + containerSourceUID = "uid" +) + +func TestMakeSinkBinding(t *testing.T) { + source := &v1alpha1.ContainerSource{ + ObjectMeta: metav1.ObjectMeta{Name: containerSourceName, Namespace: "test-namespace", UID: containerSourceUID}, + Spec: v1alpha1.ContainerSourceSpec{ + Template: corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + ServiceAccountName: "test-service-account", + Containers: []corev1.Container{ + { + Name: "test-source", + 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", + }, + }, + }, + }, + ImagePullPolicy: corev1.PullIfNotPresent, + }, + }, + }, + }, + SourceSpec: duckv1.SourceSpec{ + Sink: duckv1.Destination{ + URI: apis.HTTP("test-sink"), + }, + }, + }, + } + + want := &v1alpha1.SinkBinding{ + ObjectMeta: metav1.ObjectMeta{ + OwnerReferences: []metav1.OwnerReference{ + *kmeta.NewControllerRef(source), + }, + Name: fmt.Sprintf("%s-containersource", source.Name), + Namespace: source.Namespace, + }, + Spec: v1alpha1.SinkBindingSpec{ + SourceSpec: source.Spec.SourceSpec, + BindingSpec: duckv1alpha1.BindingSpec{ + Subject: tracker.Reference{ + APIVersion: subjectGVK.GroupVersion().String(), + Kind: subjectGVK.Kind, + Selector: &metav1.LabelSelector{ + MatchLabels: Labels(source.Name), + }, + }, + }, + }, + } + + got := MakeSinkBinding(source) + if diff := cmp.Diff(want, got); diff != "" { + t.Errorf("unexpected (-want, +got) = %v", diff) + } + +} diff --git a/pkg/reconciler/testing/containersource.go b/pkg/reconciler/testing/containersource.go index bde6944363f..e571c915f49 100644 --- a/pkg/reconciler/testing/containersource.go +++ b/pkg/reconciler/testing/containersource.go @@ -23,8 +23,6 @@ import ( appsv1 "k8s.io/api/apps/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" - "knative.dev/pkg/apis" - sourcesv1alpha1 "knative.dev/eventing/pkg/apis/sources/v1alpha1" ) @@ -57,33 +55,15 @@ func WithInitContainerSourceConditions(s *sourcesv1alpha1.ContainerSource) { s.Status.InitializeConditions() } -func WithContainerSourceSinkNotFound(msg string) ContainerSourceOption { - return func(s *sourcesv1alpha1.ContainerSource) { - s.Status.MarkNoSink("SinkNotFound", msg) - } -} - -func WithContainerSourceSinkMissing(msg string) ContainerSourceOption { - return func(s *sourcesv1alpha1.ContainerSource) { - s.Status.MarkNoSink("Missing", msg) - } -} - -func WithContainerSourceSink(uri *apis.URL) ContainerSourceOption { - return func(s *sourcesv1alpha1.ContainerSource) { - s.Status.MarkSink(uri) - } -} - -func WithContainerSourcePropagateDeploymentAvailability(d *appsv1.Deployment) ContainerSourceOption { +func WithContainerSourcePropagateReceiveAdapterStatus(d *appsv1.Deployment) ContainerSourceOption { return func(s *sourcesv1alpha1.ContainerSource) { - s.Status.PropagateDeploymentAvailability(d) + s.Status.PropagateReceiveAdapterStatus(d) } } -func WithContainerSourceDeployFailed(msg string) ContainerSourceOption { +func WithContainerSourcePropagateSinkbindingStatus(status *sourcesv1alpha1.SinkBindingStatus) ContainerSourceOption { return func(s *sourcesv1alpha1.ContainerSource) { - s.Status.MarkNotDeployed("DeploymentReconcileFailed", msg) + s.Status.PropagateSinkBindingStatus(status) } } From 9ee9fa09f68731c654b09c4948c271f4769a899f Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Thu, 26 Mar 2020 11:47:09 -0700 Subject: [PATCH 06/16] update --- .../sources/v1alpha1/container_lifecycle.go | 6 +- .../containersource/containersource.go | 37 ++- .../containersource/containersource_test.go | 256 ++++++++---------- .../containersource/controller_test.go | 3 +- .../containersource/resources/deployment.go | 2 +- .../resources/deployment_test.go | 4 +- .../containersource/resources/names.go | 30 ++ .../containersource/resources/sinkbinding.go | 7 +- .../resources/sinkbinding_test.go | 7 +- 9 files changed, 180 insertions(+), 172 deletions(-) create mode 100644 pkg/reconciler/containersource/resources/names.go diff --git a/pkg/apis/sources/v1alpha1/container_lifecycle.go b/pkg/apis/sources/v1alpha1/container_lifecycle.go index d89171259d7..16964e0d98c 100644 --- a/pkg/apis/sources/v1alpha1/container_lifecycle.go +++ b/pkg/apis/sources/v1alpha1/container_lifecycle.go @@ -57,13 +57,17 @@ func (s *ContainerSourceStatus) InitializeConditions() { // PropagateSinkBindingStatus uses the availability of the provided Deployment to determine if // ContainerSourceConditionSinkBindingReady should be marked as true, false or unknown. func (s *ContainerSourceStatus) PropagateSinkBindingStatus(status *SinkBindingStatus) { - // Do not copy conditions. + // Do not copy conditions nor observedGeneration conditions := s.Conditions + observedGeneration := s.ObservedGeneration s.SourceStatus = status.SourceStatus s.Conditions = conditions + s.ObservedGeneration = observedGeneration cond := status.GetCondition(apis.ConditionReady) switch { + case cond == nil: + containerCondSet.Manage(s).MarkUnknown(ContainerSourceConditionSinkBindingReady, "", "") case cond.Status == corev1.ConditionTrue: containerCondSet.Manage(s).MarkTrue(ContainerSourceConditionSinkBindingReady) case cond.Status == corev1.ConditionFalse: diff --git a/pkg/reconciler/containersource/containersource.go b/pkg/reconciler/containersource/containersource.go index 0db4e771f61..2be0c5fc794 100644 --- a/pkg/reconciler/containersource/containersource.go +++ b/pkg/reconciler/containersource/containersource.go @@ -21,6 +21,7 @@ import ( "fmt" "go.uber.org/zap" + appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/equality" @@ -34,13 +35,23 @@ import ( listers "knative.dev/eventing/pkg/client/listers/sources/v1alpha1" "knative.dev/eventing/pkg/logging" "knative.dev/eventing/pkg/reconciler/containersource/resources" + "knative.dev/pkg/controller" pkgreconciler "knative.dev/pkg/reconciler" ) +const ( + // Name of the corev1.Events emitted from the reconciliation process + sourceReconciled = "ContainerSourceReconciled" + deploymentCreated = "ContainerSourceDeploymentCreated" + deploymentUpdated = "ContainerSourceDeploymentUpdated" + sinkBindingCreated = "ContainerSourceSinkBindingCreated" + sinkBindingUpdated = "ContainerSourceSinkBindingUpdated" +) + // newReconciledNormal makes a new reconciler event with event type Normal, and // reason ContainerSourceReconciled. func newReconciledNormal(namespace, name string) pkgreconciler.Event { - return pkgreconciler.NewEvent(corev1.EventTypeNormal, "ContainerSourceReconciled", "ContainerSource reconciled: \"%s/%s\"", namespace, name) + return pkgreconciler.NewEvent(corev1.EventTypeNormal, sourceReconciled, "ContainerSource reconciled: \"%s/%s\"", namespace, name) } // Reconciler implements controller.Reconciler for ContainerSource resources. @@ -87,7 +98,7 @@ func (r *Reconciler) reconcileReceiveAdapter(ctx context.Context, source *v1alph if err != nil { return nil, fmt.Errorf("creating new Deployment: %v", err) } - return ra, nil + controller.GetEventRecorder(ctx).Eventf(source, corev1.EventTypeNormal, deploymentCreated, "Deployment created %q", ra.Name) } else if err != nil { return nil, fmt.Errorf("getting Deployment: %v", err) } else if !metav1.IsControlledBy(ra, source) { @@ -98,7 +109,7 @@ func (r *Reconciler) reconcileReceiveAdapter(ctx context.Context, source *v1alph if err != nil { return nil, fmt.Errorf("updating Deployment: %v", err) } - return ra, nil + controller.GetEventRecorder(ctx).Eventf(source, corev1.EventTypeNormal, deploymentUpdated, "Deployment updated %q", ra.Name) } else { logging.FromContext(ctx).Debug("Reusing existing Deployment", zap.Any("Deployment", ra)) } @@ -107,33 +118,33 @@ func (r *Reconciler) reconcileReceiveAdapter(ctx context.Context, source *v1alph return ra, nil } -func (r *Reconciler) reconcileSinkBinding(ctx context.Context, src *v1alpha1.ContainerSource) (*v1alpha1.SinkBinding, error) { +func (r *Reconciler) reconcileSinkBinding(ctx context.Context, source *v1alpha1.ContainerSource) (*v1alpha1.SinkBinding, error) { - expected := resources.MakeSinkBinding(src) + expected := resources.MakeSinkBinding(source) - sb, err := r.sinkBindingLister.SinkBindings(src.Namespace).Get(expected.Name) + sb, err := r.sinkBindingLister.SinkBindings(source.Namespace).Get(expected.Name) if apierrors.IsNotFound(err) { - sb, err = r.eventingClientSet.SourcesV1alpha1().SinkBindings(src.Namespace).Create(expected) + sb, err = r.eventingClientSet.SourcesV1alpha1().SinkBindings(source.Namespace).Create(expected) if err != nil { return nil, fmt.Errorf("creating new SinkBinding: %v", err) } - return sb, err + controller.GetEventRecorder(ctx).Eventf(source, corev1.EventTypeNormal, sinkBindingCreated, "SinkBinding created %q", sb.Name) } else if err != nil { return nil, fmt.Errorf("getting SinkBinding: %v", err) - } else if !metav1.IsControlledBy(sb, src) { - return nil, fmt.Errorf("SinkBinding %q is not owned by ContainerSource %q", sb.Name, src.Name) + } else if !metav1.IsControlledBy(sb, source) { + return nil, fmt.Errorf("SinkBinding %q is not owned by ContainerSource %q", sb.Name, source.Name) } else if r.sinkBindingSpecChanged(&sb.Spec, &expected.Spec) { sb.Spec = expected.Spec - sb, err = r.eventingClientSet.SourcesV1alpha1().SinkBindings(src.Namespace).Update(sb) + sb, err = r.eventingClientSet.SourcesV1alpha1().SinkBindings(source.Namespace).Update(sb) if err != nil { return nil, fmt.Errorf("updating SinkBinding: %v", err) } - return sb, nil + controller.GetEventRecorder(ctx).Eventf(source, corev1.EventTypeNormal, sinkBindingUpdated, "SinkBinding updated %q", sb.Name) } else { logging.FromContext(ctx).Debug("Reusing existing SinkBinding", zap.Any("SinkBinding", sb)) } - src.Status.PropagateSinkBindingStatus(&sb.Status) + source.Status.PropagateSinkBindingStatus(&sb.Status) return sb, nil } diff --git a/pkg/reconciler/containersource/containersource_test.go b/pkg/reconciler/containersource/containersource_test.go index 5b050bc0fa4..26ea2e176ba 100644 --- a/pkg/reconciler/containersource/containersource_test.go +++ b/pkg/reconciler/containersource/containersource_test.go @@ -21,6 +21,9 @@ import ( "fmt" "testing" + "knative.dev/pkg/kmeta" + "knative.dev/pkg/tracker" + appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -35,6 +38,7 @@ import ( "knative.dev/eventing/pkg/client/injection/reconciler/sources/v1alpha1/containersource" "knative.dev/eventing/pkg/reconciler/containersource/resources" duckv1 "knative.dev/pkg/apis/duck/v1" + duckv1alpha1 "knative.dev/pkg/apis/duck/v1alpha1" "knative.dev/pkg/client/injection/ducks/duck/v1/addressable" _ "knative.dev/pkg/client/injection/ducks/duck/v1/addressable/fake" "knative.dev/pkg/configmap" @@ -68,28 +72,12 @@ var ( APIVersion: "eventing.knative.dev/v1alpha1", }, } - nonsinkDestWithNamespace = duckv1.Destination{ - Ref: &duckv1.KReference{ - Name: sinkName, - Namespace: testNS, - Kind: "Trigger", - APIVersion: "eventing.knative.dev/v1alpha1", - }, - } - deploymentName = fmt.Sprintf("containersource-%s-%s", sourceName, sourceUID) + deploymentName = fmt.Sprintf("%s-deployment", sourceName) + sinkBindingName = fmt.Sprintf("%s-sinkbinding", sourceName) - // We cannot take the address of constants, so copy it into a var. - conditionTrue = corev1.ConditionTrue - - serviceDest = duckv1.Destination{ - Ref: &duckv1.KReference{ - Name: sinkName, - Kind: "Service", - APIVersion: "v1", - }, - } - serviceURI = fmt.Sprintf("http://%s.%s.svc.cluster.local/", sinkName, testNS) + conditionTrue = corev1.ConditionTrue + conditionFalse = corev1.ConditionFalse sinkDest = duckv1.Destination{ Ref: &duckv1.KReference{ @@ -98,19 +86,8 @@ var ( APIVersion: "messaging.knative.dev/v1alpha1", }, } - sinkDestWithNamespace = duckv1.Destination{ - Ref: &duckv1.KReference{ - Name: sinkName, - Namespace: testNS, - Kind: "Channel", - APIVersion: "messaging.knative.dev/v1alpha1", - }, - } - sinkDNS = "sink.mynamespace.svc." + utils.GetClusterDomainName() - sinkURI = apis.HTTP(sinkDNS) - sinkDestURI = duckv1.Destination{ - URI: apis.HTTP(sinkDNS), - } + sinkDNS = "sink.mynamespace.svc." + utils.GetClusterDomainName() + sinkURI = apis.HTTP(sinkDNS) ) func init() { @@ -131,187 +108,147 @@ func TestAllCases(t *testing.T) { // Make sure Reconcile handles good keys that don't exist. Key: "foo/not-found", }, { - Name: "missing sink", + Name: "error creating sink binding", Objects: []runtime.Object{ NewContainerSource(sourceName, testNS, + WithContainerSourceUID(sourceUID), WithContainerSourceSpec(makeContainerSourceSpec(sinkDest)), WithContainerSourceObjectMetaGeneration(generation), ), }, Key: testNS + "/" + sourceName, + WithReactors: []clientgotesting.ReactionFunc{ + InduceFailure("create", "sinkbindings"), + }, WantEvents: []string{ - Eventf(corev1.EventTypeWarning, "SinkNotFound", `Sink not found: {"ref":{"kind":"Channel","namespace":"testnamespace","name":"testsink","apiVersion":"messaging.knative.dev/v1alpha1"}}`), + Eventf(corev1.EventTypeWarning, "InternalError", "creating new SinkBinding: inducing failure for %s %s", "create", "sinkbindings"), }, + WantErr: true, WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ Object: NewContainerSource(sourceName, testNS, + WithContainerSourceUID(sourceUID), WithContainerSourceSpec(makeContainerSourceSpec(sinkDest)), WithContainerSourceObjectMetaGeneration(generation), - // Status Update: WithInitContainerSourceConditions, WithContainerSourceStatusObservedGeneration(generation), - WithContainerSourceSinkNotFound(""), ), }}, - }, { - Name: "sink not addressable", - Objects: []runtime.Object{ - NewContainerSource(sourceName, testNS, - WithContainerSourceSpec(makeContainerSourceSpec(nonsinkDest)), - WithContainerSourceObjectMetaGeneration(generation), - ), - NewTrigger(sinkName, testNS, ""), - }, - Key: testNS + "/" + sourceName, - WantEvents: []string{ - Eventf(corev1.EventTypeWarning, "SinkNotFound", `Sink not found: {"ref":{"kind":"Trigger","namespace":"testnamespace","name":"testsink","apiVersion":"eventing.knative.dev/v1alpha1"}}`), + WantCreates: []runtime.Object{ + makeSinkBinding(NewContainerSource(sourceName, testNS, + WithContainerSourceSpec(makeContainerSourceSpec(sinkDest)), + WithContainerSourceUID(sourceUID), + ), nil), }, - WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ - Object: NewContainerSource(sourceName, testNS, - WithContainerSourceSpec(makeContainerSourceSpec(nonsinkDest)), - WithContainerSourceObjectMetaGeneration(generation), - // Status Update: - WithInitContainerSourceConditions, - WithContainerSourceStatusObservedGeneration(generation), - WithContainerSourceSinkNotFound(""), - ), - }}, }, { - Name: "sink not ready", + Name: "error creating deployment", Objects: []runtime.Object{ NewContainerSource(sourceName, testNS, + WithContainerSourceUID(sourceUID), WithContainerSourceSpec(makeContainerSourceSpec(sinkDest)), WithContainerSourceObjectMetaGeneration(generation), ), - NewChannel(sinkName, testNS), }, Key: testNS + "/" + sourceName, + WithReactors: []clientgotesting.ReactionFunc{ + InduceFailure("create", "deployments"), + }, WantEvents: []string{ - Eventf(corev1.EventTypeWarning, "SinkNotFound", `Sink not found: {"ref":{"kind":"Channel","namespace":"testnamespace","name":"testsink","apiVersion":"messaging.knative.dev/v1alpha1"}}`), + Eventf(corev1.EventTypeNormal, sinkBindingCreated, "SinkBinding created %q", sinkBindingName), + Eventf(corev1.EventTypeWarning, "InternalError", "creating new Deployment: inducing failure for %s %s", "create", "deployments"), }, + WantErr: true, WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ Object: NewContainerSource(sourceName, testNS, + WithContainerSourceUID(sourceUID), WithContainerSourceSpec(makeContainerSourceSpec(sinkDest)), WithContainerSourceObjectMetaGeneration(generation), - // Status Update: WithInitContainerSourceConditions, WithContainerSourceStatusObservedGeneration(generation), - WithContainerSourceSinkNotFound(""), ), }}, + WantCreates: []runtime.Object{ + makeSinkBinding(NewContainerSource(sourceName, testNS, + WithContainerSourceSpec(makeContainerSourceSpec(sinkDest)), + WithContainerSourceUID(sourceUID), + ), nil), + makeDeployment(NewContainerSource(sourceName, testNS, + WithContainerSourceSpec(makeContainerSourceSpec(sinkDest)), + WithContainerSourceUID(sourceUID), + ), nil), + }, }, { - Name: "deployment unavailable", + Name: "successfully reconciled and not ready", Objects: []runtime.Object{ NewContainerSource(sourceName, testNS, + WithContainerSourceUID(sourceUID), WithContainerSourceSpec(makeContainerSourceSpec(sinkDest)), WithContainerSourceObjectMetaGeneration(generation), - WithContainerSourceUID(sourceUID), - ), - NewChannel(sinkName, testNS, - WithChannelAddress(sinkDNS), ), }, Key: testNS + "/" + sourceName, WantEvents: []string{ - Eventf(corev1.EventTypeNormal, "ContainerSourceReconciled", `ContainerSource reconciled: "testnamespace/test-container-source"`), + Eventf(corev1.EventTypeNormal, sinkBindingCreated, "SinkBinding created %q", sinkBindingName), + Eventf(corev1.EventTypeNormal, deploymentCreated, "Deployment created %q", deploymentName), + Eventf(corev1.EventTypeNormal, sourceReconciled, "ContainerSource reconciled: \"%s/%s\"", testNS, sourceName), }, WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ Object: NewContainerSource(sourceName, testNS, - WithContainerSourceSpec(makeContainerSourceSpec(sinkDest)), WithContainerSourceUID(sourceUID), + WithContainerSourceSpec(makeContainerSourceSpec(sinkDest)), WithContainerSourceObjectMetaGeneration(generation), - // Status Update: WithInitContainerSourceConditions, - WithContainerSourceSink(sinkURI), - WithContainerSourcePropagateDeploymentAvailability( - makeDeployment(NewContainerSource(sourceName, testNS, - WithContainerSourceSpec(makeContainerSourceSpec(sinkDest)), - WithContainerSourceUID(sourceUID), - ), nil, sinkURI, "", nil, nil)), WithContainerSourceStatusObservedGeneration(generation), + WithContainerSourcePropagateReceiveAdapterStatus(makeDeployment(NewContainerSource(sourceName, testNS, + WithContainerSourceSpec(makeContainerSourceSpec(sinkDest)), + WithContainerSourceUID(sourceUID), + ), nil)), ), }}, WantCreates: []runtime.Object{ + makeSinkBinding(NewContainerSource(sourceName, testNS, + WithContainerSourceSpec(makeContainerSourceSpec(sinkDest)), + WithContainerSourceUID(sourceUID), + ), nil), makeDeployment(NewContainerSource(sourceName, testNS, WithContainerSourceSpec(makeContainerSourceSpec(sinkDest)), WithContainerSourceUID(sourceUID), - ), nil, sinkURI, "", nil, nil), + ), nil), }, }, { - Name: "valid with ready deployment", + Name: "successfully reconciled and ready", Objects: []runtime.Object{ NewContainerSource(sourceName, testNS, - WithContainerSourceSpec(makeContainerSourceSpec(sinkDest)), WithContainerSourceUID(sourceUID), + WithContainerSourceSpec(makeContainerSourceSpec(sinkDest)), WithContainerSourceObjectMetaGeneration(generation), - WithInitContainerSourceConditions, - WithContainerSourceSink(sinkURI), - ), - NewChannel(sinkName, testNS, - WithChannelAddress(sinkDNS), ), + makeSinkBinding(NewContainerSource(sourceName, testNS, + WithContainerSourceSpec(makeContainerSourceSpec(sinkDest)), + WithContainerSourceUID(sourceUID), + ), &conditionTrue), makeDeployment(NewContainerSource(sourceName, testNS, WithContainerSourceSpec(makeContainerSourceSpec(sinkDest)), WithContainerSourceUID(sourceUID), - ), &conditionTrue, sinkURI, "", nil, nil), + ), &conditionTrue), }, Key: testNS + "/" + sourceName, WantEvents: []string{ - Eventf(corev1.EventTypeNormal, "ContainerSourceReconciled", `ContainerSource reconciled: "testnamespace/test-container-source"`), + Eventf(corev1.EventTypeNormal, sourceReconciled, "ContainerSource reconciled: \"%s/%s\"", testNS, sourceName), }, WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ Object: NewContainerSource(sourceName, testNS, - WithContainerSourceSpec(makeContainerSourceSpec(sinkDest)), WithContainerSourceUID(sourceUID), - WithContainerSourceObjectMetaGeneration(generation), - WithInitContainerSourceConditions, - WithContainerSourceSink(sinkURI), - // Status Update: - WithContainerSourcePropagateDeploymentAvailability( - makeDeployment(NewContainerSource(sourceName, testNS, - WithContainerSourceSpec(makeContainerSourceSpec(sinkDest)), - WithContainerSourceUID(sourceUID), - ), &conditionTrue, sinkURI, "", nil, nil)), - WithContainerSourceStatusObservedGeneration(generation), - ), - }}, - }, { - Name: "error for create deployment", - Objects: []runtime.Object{ - NewContainerSource(sourceName, testNS, WithContainerSourceSpec(makeContainerSourceSpec(sinkDest)), - WithContainerSourceUID(sourceUID), WithContainerSourceObjectMetaGeneration(generation), - ), - NewChannel(sinkName, testNS, - WithChannelAddress(sinkDNS), - ), - }, - Key: testNS + "/" + sourceName, - WantErr: true, - WantEvents: []string{ - Eventf(corev1.EventTypeWarning, "InternalError", "creating new deployment: inducing failure for create deployments"), - }, - WithReactors: []clientgotesting.ReactionFunc{ - InduceFailure("create", "deployments"), - }, - WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ - Object: NewContainerSource(sourceName, testNS, - WithContainerSourceSpec(makeContainerSourceSpec(sinkDest)), - WithContainerSourceUID(sourceUID), - WithContainerSourceObjectMetaGeneration(generation), - // Status Update: WithInitContainerSourceConditions, WithContainerSourceStatusObservedGeneration(generation), - WithContainerSourceSink(sinkURI), - WithContainerSourceDeployFailed(`Failed to reconcile deployment: creating new deployment: inducing failure for create deployments`), + WithContainerSourcePropagateSinkbindingStatus(makeSinkBindingStatus(&conditionTrue)), + WithContainerSourcePropagateReceiveAdapterStatus(makeDeployment(NewContainerSource(sourceName, testNS, + WithContainerSourceSpec(makeContainerSourceSpec(sinkDest)), + WithContainerSourceUID(sourceUID), + ), &conditionTrue)), ), }}, - WantCreates: []runtime.Object{ - makeDeployment(NewContainerSource(sourceName, testNS, - WithContainerSourceSpec(makeContainerSourceSpec(sinkDest)), - WithContainerSourceUID(sourceUID), - ), nil, sinkURI, "", nil, nil), - }, }, } @@ -332,19 +269,35 @@ func TestAllCases(t *testing.T) { )) } -func makeDeployment(source *sourcesv1alpha1.ContainerSource, available *corev1.ConditionStatus, sinkURI *apis.URL, ceOverrides string, labels map[string]string, annotations map[string]string) *appsv1.Deployment { - template := source.Spec.Template - - for i := range template.Spec.Containers { - template.Spec.Containers[i].Env = append(template.Spec.Containers[i].Env, corev1.EnvVar{ - Name: "K_SINK", - Value: sinkURI.String(), - }) - template.Spec.Containers[i].Env = append(template.Spec.Containers[i].Env, corev1.EnvVar{ - Name: "K_CE_OVERRIDES", - Value: ceOverrides, - }) +func makeSinkBinding(source *sourcesv1alpha1.ContainerSource, ready *corev1.ConditionStatus) *sourcesv1alpha1.SinkBinding { + sb := &sourcesv1alpha1.SinkBinding{ + ObjectMeta: metav1.ObjectMeta{ + OwnerReferences: []metav1.OwnerReference{ + *kmeta.NewControllerRef(source), + }, + Name: sinkBindingName, + Namespace: source.Namespace, + }, + Spec: sourcesv1alpha1.SinkBindingSpec{ + SourceSpec: source.Spec.SourceSpec, + BindingSpec: duckv1alpha1.BindingSpec{ + Subject: tracker.Reference{ + APIVersion: appsv1.SchemeGroupVersion.String(), + Kind: "Deployment", + Namespace: source.Namespace, + Name: resources.DeploymentName(source), + }, + }, + }, + } + if ready != nil { + sb.Status = *makeSinkBindingStatus(ready) } + return sb +} + +func makeDeployment(source *sourcesv1alpha1.ContainerSource, available *corev1.ConditionStatus) *appsv1.Deployment { + template := source.Spec.Template if template.Labels == nil { template.Labels = make(map[string]string) @@ -416,3 +369,16 @@ func makeContainerSourceSpec(sink duckv1.Destination) sourcesv1alpha1.ContainerS }, } } + +func makeSinkBindingStatus(ready *corev1.ConditionStatus) *sourcesv1alpha1.SinkBindingStatus { + return &sourcesv1alpha1.SinkBindingStatus{ + SourceStatus: duckv1.SourceStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: apis.ConditionReady, + Status: *ready, + }}, + }, + }, + } +} diff --git a/pkg/reconciler/containersource/controller_test.go b/pkg/reconciler/containersource/controller_test.go index d1025057e5e..e990c35d071 100644 --- a/pkg/reconciler/containersource/controller_test.go +++ b/pkg/reconciler/containersource/controller_test.go @@ -24,14 +24,13 @@ import ( // Fake injection informers _ "knative.dev/eventing/pkg/client/injection/informers/sources/v1alpha1/containersource/fake" - "knative.dev/pkg/client/injection/ducks/duck/v1/addressable" + _ "knative.dev/eventing/pkg/client/injection/informers/sources/v1alpha1/sinkbinding/fake" _ "knative.dev/pkg/client/injection/kube/informers/apps/v1/deployment/fake" _ "knative.dev/pkg/injection/clients/dynamicclient/fake" ) func TestNew(t *testing.T) { ctx, _ := SetupFakeContext(t) - ctx = addressable.WithDuck(ctx) c := NewController(ctx, configmap.NewStaticWatcher()) diff --git a/pkg/reconciler/containersource/resources/deployment.go b/pkg/reconciler/containersource/resources/deployment.go index fb873bf1789..38f4e5e633d 100644 --- a/pkg/reconciler/containersource/resources/deployment.go +++ b/pkg/reconciler/containersource/resources/deployment.go @@ -40,7 +40,7 @@ func MakeDeployment(source *v1alpha1.ContainerSource) *appsv1.Deployment { Kind: "Deployment", }, ObjectMeta: metav1.ObjectMeta{ - Name: kmeta.ChildName(source.Name, "-containersource" /*suffix*/), + Name: DeploymentName(source), Namespace: source.Namespace, OwnerReferences: []metav1.OwnerReference{ *kmeta.NewControllerRef(source), diff --git a/pkg/reconciler/containersource/resources/deployment_test.go b/pkg/reconciler/containersource/resources/deployment_test.go index ea1c001e5e5..c435ef5de00 100644 --- a/pkg/reconciler/containersource/resources/deployment_test.go +++ b/pkg/reconciler/containersource/resources/deployment_test.go @@ -87,7 +87,7 @@ func TestMakeDeployment(t *testing.T) { Kind: "Deployment", }, ObjectMeta: metav1.ObjectMeta{ - Name: fmt.Sprintf("%s-containersource", name), + Name: fmt.Sprintf("%s-deployment", name), Namespace: "test-namespace", OwnerReferences: []metav1.OwnerReference{{ APIVersion: "sources.knative.dev/v1alpha1", @@ -209,7 +209,7 @@ func TestMakeDeployment(t *testing.T) { Kind: "Deployment", }, ObjectMeta: metav1.ObjectMeta{ - Name: fmt.Sprintf("%s-containersource", name), + Name: fmt.Sprintf("%s-deployment", name), Namespace: "test-namespace", OwnerReferences: []metav1.OwnerReference{{ APIVersion: "sources.knative.dev/v1alpha1", diff --git a/pkg/reconciler/containersource/resources/names.go b/pkg/reconciler/containersource/resources/names.go new file mode 100644 index 00000000000..773a8fe94f8 --- /dev/null +++ b/pkg/reconciler/containersource/resources/names.go @@ -0,0 +1,30 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package resources + +import ( + "knative.dev/eventing/pkg/apis/sources/v1alpha1" + "knative.dev/pkg/kmeta" +) + +func DeploymentName(source *v1alpha1.ContainerSource) string { + return kmeta.ChildName(source.Name, "-deployment") +} + +func SinkBindingName(source *v1alpha1.ContainerSource) string { + return kmeta.ChildName(source.Name, "-sinkbinding") +} diff --git a/pkg/reconciler/containersource/resources/sinkbinding.go b/pkg/reconciler/containersource/resources/sinkbinding.go index b9812867447..64f0a0e0aaf 100644 --- a/pkg/reconciler/containersource/resources/sinkbinding.go +++ b/pkg/reconciler/containersource/resources/sinkbinding.go @@ -35,7 +35,7 @@ func MakeSinkBinding(source *v1alpha1.ContainerSource) *v1alpha1.SinkBinding { OwnerReferences: []metav1.OwnerReference{ *kmeta.NewControllerRef(source), }, - Name: kmeta.ChildName(source.Name, "-containersource" /*suffix*/), + Name: SinkBindingName(source), Namespace: source.Namespace, }, Spec: v1alpha1.SinkBindingSpec{ @@ -44,9 +44,8 @@ func MakeSinkBinding(source *v1alpha1.ContainerSource) *v1alpha1.SinkBinding { Subject: tracker.Reference{ APIVersion: subjectAPIVersion, Kind: subjectKind, - Selector: &metav1.LabelSelector{ - MatchLabels: Labels(source.Name), - }, + Namespace: source.Namespace, + Name: DeploymentName(source), }, }, }, diff --git a/pkg/reconciler/containersource/resources/sinkbinding_test.go b/pkg/reconciler/containersource/resources/sinkbinding_test.go index 4971593c239..992813bc67f 100644 --- a/pkg/reconciler/containersource/resources/sinkbinding_test.go +++ b/pkg/reconciler/containersource/resources/sinkbinding_test.go @@ -81,7 +81,7 @@ func TestMakeSinkBinding(t *testing.T) { OwnerReferences: []metav1.OwnerReference{ *kmeta.NewControllerRef(source), }, - Name: fmt.Sprintf("%s-containersource", source.Name), + Name: fmt.Sprintf("%s-sinkbinding", source.Name), Namespace: source.Namespace, }, Spec: v1alpha1.SinkBindingSpec{ @@ -90,9 +90,8 @@ func TestMakeSinkBinding(t *testing.T) { Subject: tracker.Reference{ APIVersion: subjectGVK.GroupVersion().String(), Kind: subjectGVK.Kind, - Selector: &metav1.LabelSelector{ - MatchLabels: Labels(source.Name), - }, + Namespace: source.Namespace, + Name: DeploymentName(source), }, }, }, From ead139ef39dd9b87bc66bbdac0924e079beb97fa Mon Sep 17 00:00:00 2001 From: nachocano Date: Thu, 26 Mar 2020 12:05:30 -0700 Subject: [PATCH 07/16] update codegen --- .../v1alpha1/containersource/reconciler.go | 26 +++++++++++++++---- .../containersource/stub/reconciler.go | 6 +++-- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/pkg/client/injection/reconciler/sources/v1alpha1/containersource/reconciler.go b/pkg/client/injection/reconciler/sources/v1alpha1/containersource/reconciler.go index fe9b234a4cf..017b4d64866 100644 --- a/pkg/client/injection/reconciler/sources/v1alpha1/containersource/reconciler.go +++ b/pkg/client/injection/reconciler/sources/v1alpha1/containersource/reconciler.go @@ -121,14 +121,20 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { ctx = controller.WithEventRecorder(ctx, r.Recorder) // Convert the namespace/name string into a distinct namespace and name + namespace, name, err := cache.SplitMetaNamespaceKey(key) + if err != nil { logger.Errorf("invalid resource key: %s", key) return nil } // Get the resource with this namespace/name. - original, err := r.Lister.ContainerSources(namespace).Get(name) + + getter := r.Lister.ContainerSources(namespace) + + original, err := getter.Get(name) + if errors.IsNotFound(err) { // The resource may no longer exist, in which case we stop processing. logger.Errorf("resource %q no longer exists", key) @@ -200,7 +206,10 @@ func (r *reconcilerImpl) updateStatus(existing *v1alpha1.ContainerSource, desire return reconciler.RetryUpdateConflicts(func(attempts int) (err error) { // The first iteration tries to use the injectionInformer's state, subsequent attempts fetch the latest state via API. if attempts > 0 { - existing, err = r.Client.SourcesV1alpha1().ContainerSources(desired.Namespace).Get(desired.Name, metav1.GetOptions{}) + + getter := r.Client.SourcesV1alpha1().ContainerSources(desired.Namespace) + + existing, err = getter.Get(desired.Name, metav1.GetOptions{}) if err != nil { return err } @@ -212,7 +221,10 @@ func (r *reconcilerImpl) updateStatus(existing *v1alpha1.ContainerSource, desire } existing.Status = desired.Status - _, err = r.Client.SourcesV1alpha1().ContainerSources(existing.Namespace).UpdateStatus(existing) + + updater := r.Client.SourcesV1alpha1().ContainerSources(existing.Namespace) + + _, err = updater.UpdateStatus(existing) return err }) } @@ -223,7 +235,9 @@ func (r *reconcilerImpl) updateStatus(existing *v1alpha1.ContainerSource, desire func (r *reconcilerImpl) updateFinalizersFiltered(ctx context.Context, resource *v1alpha1.ContainerSource) (*v1alpha1.ContainerSource, error) { finalizerName := defaultFinalizerName - actual, err := r.Lister.ContainerSources(resource.Namespace).Get(resource.Name) + getter := r.Lister.ContainerSources(resource.Namespace) + + actual, err := getter.Get(resource.Name) if err != nil { return resource, err } @@ -266,7 +280,9 @@ func (r *reconcilerImpl) updateFinalizersFiltered(ctx context.Context, resource return resource, err } - resource, err = r.Client.SourcesV1alpha1().ContainerSources(resource.Namespace).Patch(resource.Name, types.MergePatchType, patch) + patcher := r.Client.SourcesV1alpha1().ContainerSources(resource.Namespace) + + resource, err = patcher.Patch(resource.Name, types.MergePatchType, patch) if err != nil { r.Recorder.Eventf(resource, v1.EventTypeWarning, "FinalizerUpdateFailed", "Failed to update finalizers for %q: %v", resource.Name, err) diff --git a/pkg/client/injection/reconciler/sources/v1alpha1/containersource/stub/reconciler.go b/pkg/client/injection/reconciler/sources/v1alpha1/containersource/stub/reconciler.go index e7a65f3913c..c0d28912a3c 100644 --- a/pkg/client/injection/reconciler/sources/v1alpha1/containersource/stub/reconciler.go +++ b/pkg/client/injection/reconciler/sources/v1alpha1/containersource/stub/reconciler.go @@ -48,11 +48,13 @@ var _ containersource.Interface = (*Reconciler)(nil) // ReconcileKind implements Interface.ReconcileKind. func (r *Reconciler) ReconcileKind(ctx context.Context, o *v1alpha1.ContainerSource) reconciler.Event { - o.Status.InitializeConditions() + // TODO: use this if the resource implements InitializeConditions. + // o.Status.InitializeConditions() // TODO: add custom reconciliation logic here. - o.Status.ObservedGeneration = o.Generation + // TODO: use this if the object has .status.ObservedGeneration. + // o.Status.ObservedGeneration = o.Generation return newReconciledNormal(o.Namespace, o.Name) } From aa1f14f4eac9ba6147a9d10645ccf56fe26c29bc Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Thu, 26 Mar 2020 14:25:33 -0700 Subject: [PATCH 08/16] moving to v1alpha2 --- cmd/webhook/main.go | 2 +- config/core/resources/containersource.yaml | 2 +- pkg/apis/sources/v1alpha1/implements_test.go | 2 - .../sources/v1alpha2/container_defaults.go | 42 +++ .../v1alpha2/container_defaults_test.go | 114 +++++++ .../sources/v1alpha2/container_lifecycle.go | 92 ++++++ .../v1alpha2/container_lifecycle_test.go | 311 ++++++++++++++++++ pkg/apis/sources/v1alpha2/container_types.go | 92 ++++++ .../sources/v1alpha2/container_validation.go | 59 ++++ .../v1alpha2/container_validation_test.go | 112 +++++++ pkg/apis/sources/v1alpha2/implements_test.go | 3 + pkg/apis/sources/v1alpha2/register.go | 2 + pkg/apis/sources/v1alpha2/register_test.go | 2 + .../containersource/containersource.go | 7 +- .../containersource/resources/deployment.go | 3 +- 15 files changed, 836 insertions(+), 9 deletions(-) create mode 100644 pkg/apis/sources/v1alpha2/container_defaults.go create mode 100644 pkg/apis/sources/v1alpha2/container_defaults_test.go create mode 100644 pkg/apis/sources/v1alpha2/container_lifecycle.go create mode 100644 pkg/apis/sources/v1alpha2/container_lifecycle_test.go create mode 100644 pkg/apis/sources/v1alpha2/container_types.go create mode 100644 pkg/apis/sources/v1alpha2/container_validation.go create mode 100644 pkg/apis/sources/v1alpha2/container_validation_test.go diff --git a/cmd/webhook/main.go b/cmd/webhook/main.go index ec062d01db8..c1768efca86 100644 --- a/cmd/webhook/main.go +++ b/cmd/webhook/main.go @@ -86,11 +86,11 @@ var ourTypes = map[schema.GroupVersionKind]resourcesemantics.GenericCRD{ sourcesv1alpha1.SchemeGroupVersion.WithKind("ApiServerSource"): &sourcesv1alpha1.ApiServerSource{}, sourcesv1alpha1.SchemeGroupVersion.WithKind("PingSource"): &sourcesv1alpha1.PingSource{}, sourcesv1alpha1.SchemeGroupVersion.WithKind("SinkBinding"): &sourcesv1alpha1.SinkBinding{}, - sourcesv1alpha1.SchemeGroupVersion.WithKind("ContainerSource"): &sourcesv1alpha1.ContainerSource{}, // v1alpha2 sourcesv1alpha2.SchemeGroupVersion.WithKind("ApiServerSource"): &sourcesv1alpha2.ApiServerSource{}, sourcesv1alpha2.SchemeGroupVersion.WithKind("PingSource"): &sourcesv1alpha2.PingSource{}, sourcesv1alpha2.SchemeGroupVersion.WithKind("SinkBinding"): &sourcesv1alpha2.SinkBinding{}, + sourcesv1alpha2.SchemeGroupVersion.WithKind("ContainerSource"): &sourcesv1alpha2.ContainerSource{}, // For group flows.knative.dev // v1alpha1 diff --git a/config/core/resources/containersource.yaml b/config/core/resources/containersource.yaml index 2602817a3dc..8dd3709f9e7 100644 --- a/config/core/resources/containersource.yaml +++ b/config/core/resources/containersource.yaml @@ -57,6 +57,6 @@ spec: type: date JSONPath: .metadata.creationTimestamp versions: - - name: v1alpha1 + - name: v1alpha2 served: true storage: true diff --git a/pkg/apis/sources/v1alpha1/implements_test.go b/pkg/apis/sources/v1alpha1/implements_test.go index a7e3dd8c9ff..bfb33389d5e 100644 --- a/pkg/apis/sources/v1alpha1/implements_test.go +++ b/pkg/apis/sources/v1alpha1/implements_test.go @@ -30,8 +30,6 @@ func TestTypesImplements(t *testing.T) { {instance: &PingSource{}, iface: &duckv1.Conditions{}}, // ApiServerSource {instance: &ApiServerSource{}, iface: &duckv1.Conditions{}}, - // ContainerSource - {instance: &ContainerSource{}, iface: &duckv1.Conditions{}}, // SinkBinding {instance: &SinkBinding{}, iface: &duckv1.Conditions{}}, {instance: &SinkBinding{}, iface: &duckv1beta1.Source{}}, diff --git a/pkg/apis/sources/v1alpha2/container_defaults.go b/pkg/apis/sources/v1alpha2/container_defaults.go new file mode 100644 index 00000000000..adaadb3fb96 --- /dev/null +++ b/pkg/apis/sources/v1alpha2/container_defaults.go @@ -0,0 +1,42 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha2 + +import ( + "context" + "fmt" + + corev1 "k8s.io/api/core/v1" + "knative.dev/pkg/apis" +) + +func (s *ContainerSource) SetDefaults(ctx context.Context) { + withName := apis.WithinParent(ctx, s.ObjectMeta) + s.Spec.SetDefaults(withName) +} + +func (ss *ContainerSourceSpec) SetDefaults(ctx context.Context) { + containers := make([]corev1.Container, 0, len(ss.Template.Spec.Containers)) + for i, c := range ss.Template.Spec.Containers { + // If the Container specified has no name, then default to "_". + if c.Name == "" { + c.Name = fmt.Sprintf("%s-%d", apis.ParentMeta(ctx).Name, i) + } + containers = append(containers, c) + } + ss.Template.Spec.Containers = containers +} diff --git a/pkg/apis/sources/v1alpha2/container_defaults_test.go b/pkg/apis/sources/v1alpha2/container_defaults_test.go new file mode 100644 index 00000000000..d15060defe0 --- /dev/null +++ b/pkg/apis/sources/v1alpha2/container_defaults_test.go @@ -0,0 +1,114 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha2 + +import ( + "context" + "testing" + + "github.com/google/go-cmp/cmp" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func TestContainerSourceDefaults(t *testing.T) { + testCases := map[string]struct { + initial ContainerSource + expected ContainerSource + }{ + "no container name": { + initial: ContainerSource{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-name", + Namespace: "test-namespace", + }, + Spec: ContainerSourceSpec{ + Template: corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + Containers: []corev1.Container{{ + Image: "test-image", + }}, + }, + }, + }, + }, + expected: ContainerSource{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-name", + Namespace: "test-namespace", + }, + Spec: ContainerSourceSpec{ + Template: corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + Containers: []corev1.Container{{ + Name: "test-name-0", + Image: "test-image", + }}, + }, + }, + }, + }, + }, + "one with ontainer name one without": { + initial: ContainerSource{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-name", + Namespace: "test-namespace", + }, + Spec: ContainerSourceSpec{ + Template: corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + Containers: []corev1.Container{{ + Name: "test-container", + Image: "test-image", + }, { + Image: "test-another-image", + }}, + }, + }, + }, + }, + expected: ContainerSource{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-name", + Namespace: "test-namespace", + }, + Spec: ContainerSourceSpec{ + Template: corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + Containers: []corev1.Container{{ + Name: "test-container", + Image: "test-image", + }, { + Name: "test-name-1", + Image: "test-another-image", + }}, + }, + }, + }, + }, + }, + } + for n, tc := range testCases { + t.Run(n, func(t *testing.T) { + tc.initial.SetDefaults(context.Background()) + if diff := cmp.Diff(tc.expected, tc.initial); diff != "" { + t.Fatalf("Unexpected defaults (-want, +got): %s", diff) + } + }) + } +} diff --git a/pkg/apis/sources/v1alpha2/container_lifecycle.go b/pkg/apis/sources/v1alpha2/container_lifecycle.go new file mode 100644 index 00000000000..7cecfd380d5 --- /dev/null +++ b/pkg/apis/sources/v1alpha2/container_lifecycle.go @@ -0,0 +1,92 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha2 + +import ( + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + "knative.dev/eventing/pkg/apis/duck" + "knative.dev/pkg/apis" +) + +const ( + // ContainerSourceConditionReady has status True when the ContainerSource is ready to send events. + ContainerSourceConditionReady = apis.ConditionReady + + // ContainerSourceConditionSinkBindingReady has status True when the ContainerSource's SinkBinding is ready. + ContainerSourceConditionSinkBindingReady apis.ConditionType = "SinkBindingReady" + + // ContainerSourceConditionReceiveAdapterReady has status True when the ContainerSource's ReceiveAdapter is ready. + ContainerSourceConditionReceiveAdapterReady apis.ConditionType = "ReceiveAdapterReady" +) + +var containerCondSet = apis.NewLivingConditionSet( + ContainerSourceConditionSinkBindingReady, + ContainerSourceConditionReceiveAdapterReady, +) + +// GetCondition returns the condition currently associated with the given type, or nil. +func (s *ContainerSourceStatus) GetCondition(t apis.ConditionType) *apis.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() +} + +// PropagateSinkBindingStatus uses the availability of the provided Deployment to determine if +// ContainerSourceConditionSinkBindingReady should be marked as true, false or unknown. +func (s *ContainerSourceStatus) PropagateSinkBindingStatus(status *SinkBindingStatus) { + // Do not copy conditions nor observedGeneration + conditions := s.Conditions + observedGeneration := s.ObservedGeneration + s.SourceStatus = status.SourceStatus + s.Conditions = conditions + s.ObservedGeneration = observedGeneration + + cond := status.GetCondition(apis.ConditionReady) + switch { + case cond == nil: + containerCondSet.Manage(s).MarkUnknown(ContainerSourceConditionSinkBindingReady, "", "") + case cond.Status == corev1.ConditionTrue: + containerCondSet.Manage(s).MarkTrue(ContainerSourceConditionSinkBindingReady) + case cond.Status == corev1.ConditionFalse: + containerCondSet.Manage(s).MarkFalse(ContainerSourceConditionSinkBindingReady, cond.Reason, cond.Message) + case cond.Status == corev1.ConditionUnknown: + containerCondSet.Manage(s).MarkUnknown(ContainerSourceConditionSinkBindingReady, cond.Reason, cond.Message) + default: + containerCondSet.Manage(s).MarkUnknown(ContainerSourceConditionSinkBindingReady, cond.Reason, cond.Message) + } +} + +// PropagateReceiveAdapterStatus uses the availability of the provided Deployment to determine if +// ContainerSourceConditionReceiveAdapterReady should be marked as true or false. +func (s *ContainerSourceStatus) PropagateReceiveAdapterStatus(d *appsv1.Deployment) { + if duck.DeploymentIsAvailable(&d.Status, false) { + containerCondSet.Manage(s).MarkTrue(ContainerSourceConditionReceiveAdapterReady) + } else { + // I don't know how to propagate the status well, so just give the name of the Deployment + // for now. + containerCondSet.Manage(s).MarkFalse(ContainerSourceConditionReceiveAdapterReady, "DeploymentUnavailable", "The Deployment '%s' is unavailable.", d.Name) + } +} diff --git a/pkg/apis/sources/v1alpha2/container_lifecycle_test.go b/pkg/apis/sources/v1alpha2/container_lifecycle_test.go new file mode 100644 index 00000000000..8c6bd4ff7f2 --- /dev/null +++ b/pkg/apis/sources/v1alpha2/container_lifecycle_test.go @@ -0,0 +1,311 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha2 + +import ( + "testing" + + "github.com/google/go-cmp/cmp/cmpopts" + + "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" + "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" +) + +var ( + availDeployment = &appsv1.Deployment{ + Status: appsv1.DeploymentStatus{ + Conditions: []appsv1.DeploymentCondition{ + { + Type: appsv1.DeploymentAvailable, + Status: corev1.ConditionTrue, + }, + }, + }, + } + unavailDeployment = &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-name", + Namespace: "test-namespace", + }, + Status: appsv1.DeploymentStatus{ + Conditions: []appsv1.DeploymentCondition{ + { + Type: appsv1.DeploymentAvailable, + Status: corev1.ConditionFalse, + }, + }, + }, + } + + readySinkBinding = &SinkBinding{ + Status: SinkBindingStatus{ + SourceStatus: duckv1.SourceStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: apis.ConditionReady, + Status: corev1.ConditionTrue, + }}, + }, + }, + }, + } + + notReadySinkBinding = &SinkBinding{ + Status: SinkBindingStatus{ + SourceStatus: duckv1.SourceStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: apis.ConditionReady, + Status: corev1.ConditionFalse, + Reason: "Testing", + Message: "hi", + }}, + }, + }, + }, + } +) + +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 ready ra", + s: func() *ContainerSourceStatus { + s := &ContainerSourceStatus{} + s.InitializeConditions() + s.PropagateReceiveAdapterStatus(availDeployment) + return s + }(), + want: false, + }, { + name: "mark ready sb", + s: func() *ContainerSourceStatus { + s := &ContainerSourceStatus{} + s.InitializeConditions() + s.PropagateSinkBindingStatus(&readySinkBinding.Status) + return s + }(), + want: false, + }, { + name: "mark ready sb and ra", + s: func() *ContainerSourceStatus { + s := &ContainerSourceStatus{} + s.InitializeConditions() + s.PropagateSinkBindingStatus(&readySinkBinding.Status) + s.PropagateReceiveAdapterStatus(availDeployment) + return s + }(), + want: true, + }, { + name: "mark ready sb and ra the no sb", + s: func() *ContainerSourceStatus { + s := &ContainerSourceStatus{} + s.InitializeConditions() + s.PropagateSinkBindingStatus(&readySinkBinding.Status) + s.PropagateReceiveAdapterStatus(availDeployment) + s.PropagateSinkBindingStatus(¬ReadySinkBinding.Status) + return s + }(), + want: false, + }, { + name: "mark ready sb and ra then not ra", + s: func() *ContainerSourceStatus { + s := &ContainerSourceStatus{} + s.InitializeConditions() + s.PropagateReceiveAdapterStatus(availDeployment) + s.PropagateSinkBindingStatus(¬ReadySinkBinding.Status) + s.PropagateReceiveAdapterStatus(unavailDeployment) + return s + }(), + want: false, + }, { + name: "mark not ready sb and ready ra", + s: func() *ContainerSourceStatus { + s := &ContainerSourceStatus{} + s.InitializeConditions() + s.PropagateSinkBindingStatus(¬ReadySinkBinding.Status) + s.PropagateReceiveAdapterStatus(availDeployment) + return s + }(), + want: false, + }, { + name: "mark not ready sb and ra then ready sb", + s: func() *ContainerSourceStatus { + s := &ContainerSourceStatus{} + s.InitializeConditions() + s.PropagateSinkBindingStatus(¬ReadySinkBinding.Status) + s.PropagateReceiveAdapterStatus(availDeployment) + s.PropagateSinkBindingStatus(&readySinkBinding.Status) + 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 apis.ConditionType + want *apis.Condition + }{{ + name: "uninitialized", + s: &ContainerSourceStatus{}, + condQuery: ContainerSourceConditionReady, + want: nil, + }, { + name: "initialized", + s: func() *ContainerSourceStatus { + s := &ContainerSourceStatus{} + s.InitializeConditions() + return s + }(), + condQuery: ContainerSourceConditionReady, + want: &apis.Condition{ + Type: ContainerSourceConditionReady, + Status: corev1.ConditionUnknown, + }, + }, { + name: "mark ready ra", + s: func() *ContainerSourceStatus { + s := &ContainerSourceStatus{} + s.InitializeConditions() + s.PropagateReceiveAdapterStatus(availDeployment) + return s + }(), + condQuery: ContainerSourceConditionReady, + want: &apis.Condition{ + Type: ContainerSourceConditionReady, + Status: corev1.ConditionUnknown, + }, + }, { + name: "mark ready sb", + s: func() *ContainerSourceStatus { + s := &ContainerSourceStatus{} + s.InitializeConditions() + s.PropagateSinkBindingStatus(&readySinkBinding.Status) + return s + }(), + condQuery: ContainerSourceConditionReady, + want: &apis.Condition{ + Type: ContainerSourceConditionReady, + Status: corev1.ConditionUnknown, + }, + }, { + name: "mark ready sb and ra", + s: func() *ContainerSourceStatus { + s := &ContainerSourceStatus{} + s.InitializeConditions() + s.PropagateSinkBindingStatus(&readySinkBinding.Status) + s.PropagateReceiveAdapterStatus(availDeployment) + return s + }(), + condQuery: ContainerSourceConditionReady, + want: &apis.Condition{ + Type: ContainerSourceConditionReady, + Status: corev1.ConditionTrue, + }, + }, { + name: "mark ready sb and ra then no sb", + s: func() *ContainerSourceStatus { + s := &ContainerSourceStatus{} + s.InitializeConditions() + s.PropagateSinkBindingStatus(&readySinkBinding.Status) + s.PropagateReceiveAdapterStatus(availDeployment) + s.PropagateSinkBindingStatus(¬ReadySinkBinding.Status) + return s + }(), + condQuery: ContainerSourceConditionReady, + want: &apis.Condition{ + Type: ContainerSourceConditionReady, + Status: corev1.ConditionFalse, + Reason: "Testing", + Message: "hi", + }, + }, { + name: "mark ready sb and ra then no ra", + s: func() *ContainerSourceStatus { + s := &ContainerSourceStatus{} + s.InitializeConditions() + s.PropagateSinkBindingStatus(&readySinkBinding.Status) + s.PropagateReceiveAdapterStatus(availDeployment) + s.PropagateReceiveAdapterStatus(unavailDeployment) + return s + }(), + condQuery: ContainerSourceConditionReady, + want: &apis.Condition{ + Type: ContainerSourceConditionReady, + Status: corev1.ConditionFalse, + Reason: "DeploymentUnavailable", + Message: "The Deployment 'test-name' is unavailable.", + }, + }, { + name: "mark not ready sb and ready ra then ready sb", + s: func() *ContainerSourceStatus { + s := &ContainerSourceStatus{} + s.InitializeConditions() + s.PropagateSinkBindingStatus(¬ReadySinkBinding.Status) + s.PropagateReceiveAdapterStatus(availDeployment) + s.PropagateSinkBindingStatus(&readySinkBinding.Status) + return s + }(), + condQuery: ContainerSourceConditionReady, + want: &apis.Condition{ + Type: ContainerSourceConditionReady, + Status: corev1.ConditionTrue, + }, + }} + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := test.s.GetCondition(test.condQuery) + ignoreTime := cmpopts.IgnoreFields(apis.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/v1alpha2/container_types.go b/pkg/apis/sources/v1alpha2/container_types.go new file mode 100644 index 00000000000..795fdd97e15 --- /dev/null +++ b/pkg/apis/sources/v1alpha2/container_types.go @@ -0,0 +1,92 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha2 + +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" + "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" + "knative.dev/pkg/kmeta" +) + +// +genclient +// +genreconciler +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// 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"` +} + +var ( + _ runtime.Object = (*ContainerSource)(nil) + _ kmeta.OwnerRefable = (*ContainerSource)(nil) + _ apis.Validatable = (*ContainerSource)(nil) + _ apis.Defaultable = (*ContainerSource)(nil) + _ apis.HasSpec = (*ContainerSource)(nil) +) + +// ContainerSourceSpec defines the desired state of ContainerSource +type ContainerSourceSpec struct { + // inherits duck/v1 SourceSpec, which currently provides: + // * Sink - a reference to an object that will resolve to a domain name or + // a URI directly to use as the sink. + // * CloudEventOverrides - defines overrides to control the output format + // and modifications of the event sent to the sink. + duckv1.SourceSpec `json:",inline"` + + // Template describes the pods that will be created + Template corev1.PodTemplateSpec `json:"template"` +} + +// 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/v1 SourceStatus, 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. + // * SinkURI - the current active sink URI that has been configured for the + // Source. + duckv1.SourceStatus `json:",inline"` +} + +// +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"` +} + +// GetUntypedSpec returns the spec of the ContainerSource. +func (c *ContainerSource) GetUntypedSpec() interface{} { + return c.Spec +} diff --git a/pkg/apis/sources/v1alpha2/container_validation.go b/pkg/apis/sources/v1alpha2/container_validation.go new file mode 100644 index 00000000000..167435bfa1d --- /dev/null +++ b/pkg/apis/sources/v1alpha2/container_validation.go @@ -0,0 +1,59 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha2 + +import ( + "context" + + corev1 "k8s.io/api/core/v1" + "knative.dev/pkg/apis" +) + +func (c *ContainerSource) Validate(ctx context.Context) *apis.FieldError { + return c.Spec.Validate(ctx).ViaField("spec") +} + +func (cs *ContainerSourceSpec) Validate(ctx context.Context) *apis.FieldError { + var errs *apis.FieldError + if fe := cs.Sink.Validate(ctx); fe != nil { + errs = errs.Also(fe.ViaField("sink")) + } + + // Validate there is at least a container + if cs.Template.Spec.Containers == nil || len(cs.Template.Spec.Containers) == 0 { + fe := apis.ErrMissingField("containers") + errs = errs.Also(fe) + } else { + for i, c := range cs.Template.Spec.Containers { + if ce := isValidContainer(&c); ce != nil { + errs = errs.Also(ce.ViaFieldIndex("containers", i)) + } + } + } + return errs +} + +func isValidContainer(c *corev1.Container) *apis.FieldError { + var errs *apis.FieldError + if c.Name == "" { + errs = errs.Also(apis.ErrMissingField("name")) + } + if c.Image == "" { + errs = errs.Also(apis.ErrMissingField("image")) + } + return errs +} diff --git a/pkg/apis/sources/v1alpha2/container_validation_test.go b/pkg/apis/sources/v1alpha2/container_validation_test.go new file mode 100644 index 00000000000..6d46e31eba4 --- /dev/null +++ b/pkg/apis/sources/v1alpha2/container_validation_test.go @@ -0,0 +1,112 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha2 + +import ( + "context" + "testing" + + "github.com/google/go-cmp/cmp" + corev1 "k8s.io/api/core/v1" + "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" +) + +func TestContainerSourceValidation(t *testing.T) { + tests := []struct { + name string + spec ContainerSourceSpec + want *apis.FieldError + }{{ + name: "missing container", + spec: ContainerSourceSpec{ + Template: corev1.PodTemplateSpec{}, + SourceSpec: duckv1.SourceSpec{ + Sink: duckv1.Destination{ + Ref: &duckv1.KReference{ + APIVersion: "v1alpha1", + Kind: "Broker", + Name: "default", + }, + }, + }, + }, + want: func() *apis.FieldError { + var errs *apis.FieldError + fe := apis.ErrMissingField("containers") + errs = errs.Also(fe) + return errs + }(), + }, { + name: "missing container image", + spec: ContainerSourceSpec{ + Template: corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + Containers: []corev1.Container{{ + Name: "test-name", + }}, + }, + }, + SourceSpec: duckv1.SourceSpec{ + Sink: duckv1.Destination{ + Ref: &duckv1.KReference{ + APIVersion: "eventing.knative.dev/v1alpha1", + Kind: "Broker", + Name: "default", + }, + }, + }, + }, + want: func() *apis.FieldError { + var errs *apis.FieldError + fe := apis.ErrMissingField("containers[0].image") + errs = errs.Also(fe) + return errs + }(), + }, { + name: "empty sink", + spec: ContainerSourceSpec{ + Template: corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + Containers: []corev1.Container{{ + Name: "name", + Image: "image", + }}, + }, + }, + SourceSpec: duckv1.SourceSpec{ + Sink: duckv1.Destination{}, + }, + }, + want: func() *apis.FieldError { + var errs *apis.FieldError + fe := apis.ErrGeneric("expected at least one, got none", "sink.ref", "sink.uri") + errs = errs.Also(fe) + return errs + }(), + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := test.spec.Validate(context.TODO()) + if diff := cmp.Diff(test.want.Error(), got.Error()); diff != "" { + t.Errorf("ContainerSourceSpec.Validate (-want, +got) = %v", diff) + } + }) + } +} diff --git a/pkg/apis/sources/v1alpha2/implements_test.go b/pkg/apis/sources/v1alpha2/implements_test.go index 774f1fe1df5..91ccb16f71c 100644 --- a/pkg/apis/sources/v1alpha2/implements_test.go +++ b/pkg/apis/sources/v1alpha2/implements_test.go @@ -27,6 +27,9 @@ func TestTypesImplements(t *testing.T) { // PingSource {instance: &PingSource{}, iface: &duckv1.Conditions{}}, {instance: &PingSource{}, iface: &duckv1.Source{}}, + // ContainerSource + {instance: &ContainerSource{}, iface: &duckv1.Conditions{}}, + {instance: &ContainerSource{}, iface: &duckv1.Source{}}, // ApiServerSource //{instance: &ApiServerSource{}, iface: &duckv1.Conditions{}}, //{instance: &ApiServerSource{}, iface: &duckv1.Source{}}, diff --git a/pkg/apis/sources/v1alpha2/register.go b/pkg/apis/sources/v1alpha2/register.go index 9f57ddeb4ad..e33d6c76cab 100644 --- a/pkg/apis/sources/v1alpha2/register.go +++ b/pkg/apis/sources/v1alpha2/register.go @@ -51,6 +51,8 @@ func addKnownTypes(scheme *runtime.Scheme) error { &PingSourceList{}, &SinkBinding{}, &SinkBindingList{}, + &ContainerSource{}, + &ContainerSourceList{}, ) metav1.AddToGroupVersion(scheme, SchemeGroupVersion) return nil diff --git a/pkg/apis/sources/v1alpha2/register_test.go b/pkg/apis/sources/v1alpha2/register_test.go index b687ac9ce7f..5050fdc0cdb 100644 --- a/pkg/apis/sources/v1alpha2/register_test.go +++ b/pkg/apis/sources/v1alpha2/register_test.go @@ -66,6 +66,8 @@ func TestKnownTypes(t *testing.T) { "SinkBindingList", "PingSource", "PingSourceList", + "ContainerSource", + "ContainerSourceList", } { if _, ok := types[name]; !ok { t.Errorf("Did not find %q as registered type", name) diff --git a/pkg/reconciler/containersource/containersource.go b/pkg/reconciler/containersource/containersource.go index 2be0c5fc794..5b3122122de 100644 --- a/pkg/reconciler/containersource/containersource.go +++ b/pkg/reconciler/containersource/containersource.go @@ -19,6 +19,7 @@ package containersource import ( "context" "fmt" + "knative.dev/eventing/pkg/apis/sources/v1alpha1" "go.uber.org/zap" @@ -29,7 +30,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" appsv1listers "k8s.io/client-go/listers/apps/v1" - "knative.dev/eventing/pkg/apis/sources/v1alpha1" + "knative.dev/eventing/pkg/apis/sources/v1alpha2" clientset "knative.dev/eventing/pkg/client/clientset/versioned" "knative.dev/eventing/pkg/client/injection/reconciler/sources/v1alpha1/containersource" listers "knative.dev/eventing/pkg/client/listers/sources/v1alpha1" @@ -69,7 +70,7 @@ type Reconciler struct { var _ containersource.Interface = (*Reconciler)(nil) // ReconcileKind implements Interface.ReconcileKind. -func (r *Reconciler) ReconcileKind(ctx context.Context, source *v1alpha1.ContainerSource) pkgreconciler.Event { +func (r *Reconciler) ReconcileKind(ctx context.Context, source *v1alpha2.ContainerSource) pkgreconciler.Event { source.Status.InitializeConditions() source.Status.ObservedGeneration = source.Generation @@ -88,7 +89,7 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, source *v1alpha1.Contain return newReconciledNormal(source.Namespace, source.Name) } -func (r *Reconciler) reconcileReceiveAdapter(ctx context.Context, source *v1alpha1.ContainerSource) (*appsv1.Deployment, error) { +func (r *Reconciler) reconcileReceiveAdapter(ctx context.Context, source *v1alpha2.ContainerSource) (*appsv1.Deployment, error) { expected := resources.MakeDeployment(source) diff --git a/pkg/reconciler/containersource/resources/deployment.go b/pkg/reconciler/containersource/resources/deployment.go index 38f4e5e633d..e87de9eaa32 100644 --- a/pkg/reconciler/containersource/resources/deployment.go +++ b/pkg/reconciler/containersource/resources/deployment.go @@ -20,11 +20,10 @@ import ( appsv1 "k8s.io/api/apps/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "knative.dev/eventing/pkg/apis/sources/v1alpha1" "knative.dev/pkg/kmeta" ) -func MakeDeployment(source *v1alpha1.ContainerSource) *appsv1.Deployment { +func MakeDeployment(source *v1alpha2.ContainerSource) *appsv1.Deployment { template := source.Spec.Template if template.Labels == nil { template.Labels = make(map[string]string) From 9e1bd55262809d438932b60e006bc92651e2d92f Mon Sep 17 00:00:00 2001 From: nachocano Date: Thu, 26 Mar 2020 14:27:26 -0700 Subject: [PATCH 09/16] update code gen --- .../sources/v1alpha2/zz_generated.deepcopy.go | 96 +++++ .../typed/sources/v1alpha2/containersource.go | 191 ++++++++++ .../v1alpha2/fake/fake_containersource.go | 140 ++++++++ .../v1alpha2/fake/fake_sources_client.go | 4 + .../sources/v1alpha2/generated_expansion.go | 2 + .../typed/sources/v1alpha2/sources_client.go | 5 + .../informers/externalversions/generic.go | 2 + .../sources/v1alpha2/containersource.go | 89 +++++ .../sources/v1alpha2/interface.go | 7 + .../containersource/containersource.go | 52 +++ .../v1alpha2/containersource/fake/fake.go | 40 +++ .../v1alpha2/containersource/controller.go | 97 +++++ .../v1alpha2/containersource/reconciler.go | 339 ++++++++++++++++++ .../containersource/stub/controller.go | 54 +++ .../containersource/stub/reconciler.go | 66 ++++ .../sources/v1alpha2/containersource.go | 94 +++++ .../sources/v1alpha2/expansion_generated.go | 8 + 17 files changed, 1286 insertions(+) create mode 100644 pkg/client/clientset/versioned/typed/sources/v1alpha2/containersource.go create mode 100644 pkg/client/clientset/versioned/typed/sources/v1alpha2/fake/fake_containersource.go create mode 100644 pkg/client/informers/externalversions/sources/v1alpha2/containersource.go create mode 100644 pkg/client/injection/informers/sources/v1alpha2/containersource/containersource.go create mode 100644 pkg/client/injection/informers/sources/v1alpha2/containersource/fake/fake.go create mode 100644 pkg/client/injection/reconciler/sources/v1alpha2/containersource/controller.go create mode 100644 pkg/client/injection/reconciler/sources/v1alpha2/containersource/reconciler.go create mode 100644 pkg/client/injection/reconciler/sources/v1alpha2/containersource/stub/controller.go create mode 100644 pkg/client/injection/reconciler/sources/v1alpha2/containersource/stub/reconciler.go create mode 100644 pkg/client/listers/sources/v1alpha2/containersource.go diff --git a/pkg/apis/sources/v1alpha2/zz_generated.deepcopy.go b/pkg/apis/sources/v1alpha2/zz_generated.deepcopy.go index eb0f9f7092b..7bf7ad702ce 100644 --- a/pkg/apis/sources/v1alpha2/zz_generated.deepcopy.go +++ b/pkg/apis/sources/v1alpha2/zz_generated.deepcopy.go @@ -163,6 +163,102 @@ func (in *ApiServerSourceStatus) DeepCopy() *ApiServerSourceStatus { 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 + in.ListMeta.DeepCopyInto(&out.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 + in.SourceSpec.DeepCopyInto(&out.SourceSpec) + in.Template.DeepCopyInto(&out.Template) + 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.SourceStatus.DeepCopyInto(&out.SourceStatus) + 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 *PingSource) DeepCopyInto(out *PingSource) { *out = *in diff --git a/pkg/client/clientset/versioned/typed/sources/v1alpha2/containersource.go b/pkg/client/clientset/versioned/typed/sources/v1alpha2/containersource.go new file mode 100644 index 00000000000..1e884bf20c9 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/sources/v1alpha2/containersource.go @@ -0,0 +1,191 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha2 + +import ( + "time" + + 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" + v1alpha2 "knative.dev/eventing/pkg/apis/sources/v1alpha2" + scheme "knative.dev/eventing/pkg/client/clientset/versioned/scheme" +) + +// 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(*v1alpha2.ContainerSource) (*v1alpha2.ContainerSource, error) + Update(*v1alpha2.ContainerSource) (*v1alpha2.ContainerSource, error) + UpdateStatus(*v1alpha2.ContainerSource) (*v1alpha2.ContainerSource, error) + Delete(name string, options *v1.DeleteOptions) error + DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error + Get(name string, options v1.GetOptions) (*v1alpha2.ContainerSource, error) + List(opts v1.ListOptions) (*v1alpha2.ContainerSourceList, error) + Watch(opts v1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha2.ContainerSource, err error) + ContainerSourceExpansion +} + +// containerSources implements ContainerSourceInterface +type containerSources struct { + client rest.Interface + ns string +} + +// newContainerSources returns a ContainerSources +func newContainerSources(c *SourcesV1alpha2Client, 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 *v1alpha2.ContainerSource, err error) { + result = &v1alpha2.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 *v1alpha2.ContainerSourceList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1alpha2.ContainerSourceList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("containersources"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested containerSources. +func (c *containerSources) Watch(opts v1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("containersources"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + 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 *v1alpha2.ContainerSource) (result *v1alpha2.ContainerSource, err error) { + result = &v1alpha2.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 *v1alpha2.ContainerSource) (result *v1alpha2.ContainerSource, err error) { + result = &v1alpha2.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 *v1alpha2.ContainerSource) (result *v1alpha2.ContainerSource, err error) { + result = &v1alpha2.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 { + var timeout time.Duration + if listOptions.TimeoutSeconds != nil { + timeout = time.Duration(*listOptions.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Namespace(c.ns). + Resource("containersources"). + VersionedParams(&listOptions, scheme.ParameterCodec). + Timeout(timeout). + 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 *v1alpha2.ContainerSource, err error) { + result = &v1alpha2.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/v1alpha2/fake/fake_containersource.go b/pkg/client/clientset/versioned/typed/sources/v1alpha2/fake/fake_containersource.go new file mode 100644 index 00000000000..c990e643f2a --- /dev/null +++ b/pkg/client/clientset/versioned/typed/sources/v1alpha2/fake/fake_containersource.go @@ -0,0 +1,140 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + v1alpha2 "knative.dev/eventing/pkg/apis/sources/v1alpha2" +) + +// FakeContainerSources implements ContainerSourceInterface +type FakeContainerSources struct { + Fake *FakeSourcesV1alpha2 + ns string +} + +var containersourcesResource = schema.GroupVersionResource{Group: "sources.knative.dev", Version: "v1alpha2", Resource: "containersources"} + +var containersourcesKind = schema.GroupVersionKind{Group: "sources.knative.dev", Version: "v1alpha2", 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 *v1alpha2.ContainerSource, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(containersourcesResource, c.ns, name), &v1alpha2.ContainerSource{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha2.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 *v1alpha2.ContainerSourceList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(containersourcesResource, containersourcesKind, c.ns, opts), &v1alpha2.ContainerSourceList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha2.ContainerSourceList{ListMeta: obj.(*v1alpha2.ContainerSourceList).ListMeta} + for _, item := range obj.(*v1alpha2.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 *v1alpha2.ContainerSource) (result *v1alpha2.ContainerSource, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(containersourcesResource, c.ns, containerSource), &v1alpha2.ContainerSource{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha2.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 *v1alpha2.ContainerSource) (result *v1alpha2.ContainerSource, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(containersourcesResource, c.ns, containerSource), &v1alpha2.ContainerSource{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha2.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 *v1alpha2.ContainerSource) (*v1alpha2.ContainerSource, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(containersourcesResource, "status", c.ns, containerSource), &v1alpha2.ContainerSource{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha2.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), &v1alpha2.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, &v1alpha2.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 *v1alpha2.ContainerSource, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(containersourcesResource, c.ns, name, pt, data, subresources...), &v1alpha2.ContainerSource{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha2.ContainerSource), err +} diff --git a/pkg/client/clientset/versioned/typed/sources/v1alpha2/fake/fake_sources_client.go b/pkg/client/clientset/versioned/typed/sources/v1alpha2/fake/fake_sources_client.go index 3459a1a0d55..fb6365ba9da 100644 --- a/pkg/client/clientset/versioned/typed/sources/v1alpha2/fake/fake_sources_client.go +++ b/pkg/client/clientset/versioned/typed/sources/v1alpha2/fake/fake_sources_client.go @@ -32,6 +32,10 @@ func (c *FakeSourcesV1alpha2) ApiServerSources(namespace string) v1alpha2.ApiSer return &FakeApiServerSources{c, namespace} } +func (c *FakeSourcesV1alpha2) ContainerSources(namespace string) v1alpha2.ContainerSourceInterface { + return &FakeContainerSources{c, namespace} +} + func (c *FakeSourcesV1alpha2) PingSources(namespace string) v1alpha2.PingSourceInterface { return &FakePingSources{c, namespace} } diff --git a/pkg/client/clientset/versioned/typed/sources/v1alpha2/generated_expansion.go b/pkg/client/clientset/versioned/typed/sources/v1alpha2/generated_expansion.go index c4f05376cfd..b2816d38c5f 100644 --- a/pkg/client/clientset/versioned/typed/sources/v1alpha2/generated_expansion.go +++ b/pkg/client/clientset/versioned/typed/sources/v1alpha2/generated_expansion.go @@ -20,6 +20,8 @@ package v1alpha2 type ApiServerSourceExpansion interface{} +type ContainerSourceExpansion interface{} + type PingSourceExpansion interface{} type SinkBindingExpansion interface{} diff --git a/pkg/client/clientset/versioned/typed/sources/v1alpha2/sources_client.go b/pkg/client/clientset/versioned/typed/sources/v1alpha2/sources_client.go index 1061b14e0f5..e573e6dcadc 100644 --- a/pkg/client/clientset/versioned/typed/sources/v1alpha2/sources_client.go +++ b/pkg/client/clientset/versioned/typed/sources/v1alpha2/sources_client.go @@ -27,6 +27,7 @@ import ( type SourcesV1alpha2Interface interface { RESTClient() rest.Interface ApiServerSourcesGetter + ContainerSourcesGetter PingSourcesGetter SinkBindingsGetter } @@ -40,6 +41,10 @@ func (c *SourcesV1alpha2Client) ApiServerSources(namespace string) ApiServerSour return newApiServerSources(c, namespace) } +func (c *SourcesV1alpha2Client) ContainerSources(namespace string) ContainerSourceInterface { + return newContainerSources(c, namespace) +} + func (c *SourcesV1alpha2Client) PingSources(namespace string) PingSourceInterface { return newPingSources(c, namespace) } diff --git a/pkg/client/informers/externalversions/generic.go b/pkg/client/informers/externalversions/generic.go index fb59e139586..60abc746c72 100644 --- a/pkg/client/informers/externalversions/generic.go +++ b/pkg/client/informers/externalversions/generic.go @@ -121,6 +121,8 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource // Group=sources.knative.dev, Version=v1alpha2 case v1alpha2.SchemeGroupVersion.WithResource("apiserversources"): return &genericInformer{resource: resource.GroupResource(), informer: f.Sources().V1alpha2().ApiServerSources().Informer()}, nil + case v1alpha2.SchemeGroupVersion.WithResource("containersources"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Sources().V1alpha2().ContainerSources().Informer()}, nil case v1alpha2.SchemeGroupVersion.WithResource("pingsources"): return &genericInformer{resource: resource.GroupResource(), informer: f.Sources().V1alpha2().PingSources().Informer()}, nil case v1alpha2.SchemeGroupVersion.WithResource("sinkbindings"): diff --git a/pkg/client/informers/externalversions/sources/v1alpha2/containersource.go b/pkg/client/informers/externalversions/sources/v1alpha2/containersource.go new file mode 100644 index 00000000000..0c25af1ed58 --- /dev/null +++ b/pkg/client/informers/externalversions/sources/v1alpha2/containersource.go @@ -0,0 +1,89 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1alpha2 + +import ( + time "time" + + 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" + sourcesv1alpha2 "knative.dev/eventing/pkg/apis/sources/v1alpha2" + versioned "knative.dev/eventing/pkg/client/clientset/versioned" + internalinterfaces "knative.dev/eventing/pkg/client/informers/externalversions/internalinterfaces" + v1alpha2 "knative.dev/eventing/pkg/client/listers/sources/v1alpha2" +) + +// ContainerSourceInformer provides access to a shared informer and lister for +// ContainerSources. +type ContainerSourceInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1alpha2.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.SourcesV1alpha2().ContainerSources(namespace).List(options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.SourcesV1alpha2().ContainerSources(namespace).Watch(options) + }, + }, + &sourcesv1alpha2.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(&sourcesv1alpha2.ContainerSource{}, f.defaultInformer) +} + +func (f *containerSourceInformer) Lister() v1alpha2.ContainerSourceLister { + return v1alpha2.NewContainerSourceLister(f.Informer().GetIndexer()) +} diff --git a/pkg/client/informers/externalversions/sources/v1alpha2/interface.go b/pkg/client/informers/externalversions/sources/v1alpha2/interface.go index 33a90142ca7..164586caa3c 100644 --- a/pkg/client/informers/externalversions/sources/v1alpha2/interface.go +++ b/pkg/client/informers/externalversions/sources/v1alpha2/interface.go @@ -26,6 +26,8 @@ import ( type Interface interface { // ApiServerSources returns a ApiServerSourceInformer. ApiServerSources() ApiServerSourceInformer + // ContainerSources returns a ContainerSourceInformer. + ContainerSources() ContainerSourceInformer // PingSources returns a PingSourceInformer. PingSources() PingSourceInformer // SinkBindings returns a SinkBindingInformer. @@ -48,6 +50,11 @@ func (v *version) ApiServerSources() ApiServerSourceInformer { return &apiServerSourceInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} } +// ContainerSources returns a ContainerSourceInformer. +func (v *version) ContainerSources() ContainerSourceInformer { + return &containerSourceInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} + // PingSources returns a PingSourceInformer. func (v *version) PingSources() PingSourceInformer { return &pingSourceInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} diff --git a/pkg/client/injection/informers/sources/v1alpha2/containersource/containersource.go b/pkg/client/injection/informers/sources/v1alpha2/containersource/containersource.go new file mode 100644 index 00000000000..7c3828e14f8 --- /dev/null +++ b/pkg/client/injection/informers/sources/v1alpha2/containersource/containersource.go @@ -0,0 +1,52 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package containersource + +import ( + context "context" + + v1alpha2 "knative.dev/eventing/pkg/client/informers/externalversions/sources/v1alpha2" + factory "knative.dev/eventing/pkg/client/injection/informers/factory" + controller "knative.dev/pkg/controller" + injection "knative.dev/pkg/injection" + logging "knative.dev/pkg/logging" +) + +func init() { + injection.Default.RegisterInformer(withInformer) +} + +// Key is used for associating the Informer inside the context.Context. +type Key struct{} + +func withInformer(ctx context.Context) (context.Context, controller.Informer) { + f := factory.Get(ctx) + inf := f.Sources().V1alpha2().ContainerSources() + return context.WithValue(ctx, Key{}, inf), inf.Informer() +} + +// Get extracts the typed informer from the context. +func Get(ctx context.Context) v1alpha2.ContainerSourceInformer { + untyped := ctx.Value(Key{}) + if untyped == nil { + logging.FromContext(ctx).Panic( + "Unable to fetch knative.dev/eventing/pkg/client/informers/externalversions/sources/v1alpha2.ContainerSourceInformer from context.") + } + return untyped.(v1alpha2.ContainerSourceInformer) +} diff --git a/pkg/client/injection/informers/sources/v1alpha2/containersource/fake/fake.go b/pkg/client/injection/informers/sources/v1alpha2/containersource/fake/fake.go new file mode 100644 index 00000000000..c26d4ccca08 --- /dev/null +++ b/pkg/client/injection/informers/sources/v1alpha2/containersource/fake/fake.go @@ -0,0 +1,40 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package fake + +import ( + context "context" + + fake "knative.dev/eventing/pkg/client/injection/informers/factory/fake" + containersource "knative.dev/eventing/pkg/client/injection/informers/sources/v1alpha2/containersource" + controller "knative.dev/pkg/controller" + injection "knative.dev/pkg/injection" +) + +var Get = containersource.Get + +func init() { + injection.Fake.RegisterInformer(withInformer) +} + +func withInformer(ctx context.Context) (context.Context, controller.Informer) { + f := fake.Get(ctx) + inf := f.Sources().V1alpha2().ContainerSources() + return context.WithValue(ctx, containersource.Key{}, inf), inf.Informer() +} diff --git a/pkg/client/injection/reconciler/sources/v1alpha2/containersource/controller.go b/pkg/client/injection/reconciler/sources/v1alpha2/containersource/controller.go new file mode 100644 index 00000000000..758b5521b65 --- /dev/null +++ b/pkg/client/injection/reconciler/sources/v1alpha2/containersource/controller.go @@ -0,0 +1,97 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package containersource + +import ( + context "context" + + corev1 "k8s.io/api/core/v1" + watch "k8s.io/apimachinery/pkg/watch" + scheme "k8s.io/client-go/kubernetes/scheme" + v1 "k8s.io/client-go/kubernetes/typed/core/v1" + record "k8s.io/client-go/tools/record" + versionedscheme "knative.dev/eventing/pkg/client/clientset/versioned/scheme" + injectionclient "knative.dev/eventing/pkg/client/injection/client" + containersource "knative.dev/eventing/pkg/client/injection/informers/sources/v1alpha2/containersource" + client "knative.dev/pkg/client/injection/kube/client" + controller "knative.dev/pkg/controller" + logging "knative.dev/pkg/logging" +) + +const ( + defaultControllerAgentName = "containersource-controller" + defaultFinalizerName = "containersources.sources.knative.dev" + defaultQueueName = "containersources" +) + +// NewImpl returns a controller.Impl that handles queuing and feeding work from +// the queue through an implementation of controller.Reconciler, delegating to +// the provided Interface and optional Finalizer methods. OptionsFn is used to return +// controller.Options to be used but the internal reconciler. +func NewImpl(ctx context.Context, r Interface, optionsFns ...controller.OptionsFn) *controller.Impl { + logger := logging.FromContext(ctx) + + // Check the options function input. It should be 0 or 1. + if len(optionsFns) > 1 { + logger.Fatalf("up to one options function is supported, found %d", len(optionsFns)) + } + + containersourceInformer := containersource.Get(ctx) + + recorder := controller.GetEventRecorder(ctx) + if recorder == nil { + // Create event broadcaster + logger.Debug("Creating event broadcaster") + eventBroadcaster := record.NewBroadcaster() + watches := []watch.Interface{ + eventBroadcaster.StartLogging(logger.Named("event-broadcaster").Infof), + eventBroadcaster.StartRecordingToSink( + &v1.EventSinkImpl{Interface: client.Get(ctx).CoreV1().Events("")}), + } + recorder = eventBroadcaster.NewRecorder(scheme.Scheme, corev1.EventSource{Component: defaultControllerAgentName}) + go func() { + <-ctx.Done() + for _, w := range watches { + w.Stop() + } + }() + } + + rec := &reconcilerImpl{ + Client: injectionclient.Get(ctx), + Lister: containersourceInformer.Lister(), + Recorder: recorder, + reconciler: r, + } + impl := controller.NewImpl(rec, logger, defaultQueueName) + + // Pass impl to the options. Save any optional results. + for _, fn := range optionsFns { + opts := fn(impl) + if opts.ConfigStore != nil { + rec.configStore = opts.ConfigStore + } + } + + return impl +} + +func init() { + versionedscheme.AddToScheme(scheme.Scheme) +} diff --git a/pkg/client/injection/reconciler/sources/v1alpha2/containersource/reconciler.go b/pkg/client/injection/reconciler/sources/v1alpha2/containersource/reconciler.go new file mode 100644 index 00000000000..290ce9b311a --- /dev/null +++ b/pkg/client/injection/reconciler/sources/v1alpha2/containersource/reconciler.go @@ -0,0 +1,339 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package containersource + +import ( + context "context" + "encoding/json" + "reflect" + + zap "go.uber.org/zap" + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/equality" + errors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + sets "k8s.io/apimachinery/pkg/util/sets" + cache "k8s.io/client-go/tools/cache" + record "k8s.io/client-go/tools/record" + v1alpha2 "knative.dev/eventing/pkg/apis/sources/v1alpha2" + versioned "knative.dev/eventing/pkg/client/clientset/versioned" + sourcesv1alpha2 "knative.dev/eventing/pkg/client/listers/sources/v1alpha2" + controller "knative.dev/pkg/controller" + logging "knative.dev/pkg/logging" + reconciler "knative.dev/pkg/reconciler" +) + +// Interface defines the strongly typed interfaces to be implemented by a +// controller reconciling v1alpha2.ContainerSource. +type Interface interface { + // ReconcileKind implements custom logic to reconcile v1alpha2.ContainerSource. Any changes + // to the objects .Status or .Finalizers will be propagated to the stored + // object. It is recommended that implementors do not call any update calls + // for the Kind inside of ReconcileKind, it is the responsibility of the calling + // controller to propagate those properties. The resource passed to ReconcileKind + // will always have an empty deletion timestamp. + ReconcileKind(ctx context.Context, o *v1alpha2.ContainerSource) reconciler.Event +} + +// Finalizer defines the strongly typed interfaces to be implemented by a +// controller finalizing v1alpha2.ContainerSource. +type Finalizer interface { + // FinalizeKind implements custom logic to finalize v1alpha2.ContainerSource. Any changes + // to the objects .Status or .Finalizers will be ignored. Returning a nil or + // Normal type reconciler.Event will allow the finalizer to be deleted on + // the resource. The resource passed to FinalizeKind will always have a set + // deletion timestamp. + FinalizeKind(ctx context.Context, o *v1alpha2.ContainerSource) reconciler.Event +} + +// reconcilerImpl implements controller.Reconciler for v1alpha2.ContainerSource resources. +type reconcilerImpl struct { + // Client is used to write back status updates. + Client versioned.Interface + + // Listers index properties about resources + Lister sourcesv1alpha2.ContainerSourceLister + + // Recorder is an event recorder for recording Event resources to the + // Kubernetes API. + Recorder record.EventRecorder + + // configStore allows for decorating a context with config maps. + // +optional + configStore reconciler.ConfigStore + + // reconciler is the implementation of the business logic of the resource. + reconciler Interface +} + +// Check that our Reconciler implements controller.Reconciler +var _ controller.Reconciler = (*reconcilerImpl)(nil) + +func NewReconciler(ctx context.Context, logger *zap.SugaredLogger, client versioned.Interface, lister sourcesv1alpha2.ContainerSourceLister, recorder record.EventRecorder, r Interface, options ...controller.Options) controller.Reconciler { + // Check the options function input. It should be 0 or 1. + if len(options) > 1 { + logger.Fatalf("up to one options struct is supported, found %d", len(options)) + } + + rec := &reconcilerImpl{ + Client: client, + Lister: lister, + Recorder: recorder, + reconciler: r, + } + + for _, opts := range options { + if opts.ConfigStore != nil { + rec.configStore = opts.ConfigStore + } + } + + return rec +} + +// Reconcile implements controller.Reconciler +func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { + logger := logging.FromContext(ctx) + + // If configStore is set, attach the frozen configuration to the context. + if r.configStore != nil { + ctx = r.configStore.ToContext(ctx) + } + + // Add the recorder to context. + ctx = controller.WithEventRecorder(ctx, r.Recorder) + + // Convert the namespace/name string into a distinct namespace and name + + namespace, name, err := cache.SplitMetaNamespaceKey(key) + + if err != nil { + logger.Errorf("invalid resource key: %s", key) + return nil + } + + // Get the resource with this namespace/name. + + getter := r.Lister.ContainerSources(namespace) + + original, err := getter.Get(name) + + if errors.IsNotFound(err) { + // The resource may no longer exist, in which case we stop processing. + logger.Errorf("resource %q no longer exists", key) + return nil + } else if err != nil { + return err + } + + // Don't modify the informers copy. + resource := original.DeepCopy() + + var reconcileEvent reconciler.Event + if resource.GetDeletionTimestamp().IsZero() { + // Append the target method to the logger. + logger = logger.With(zap.String("targetMethod", "ReconcileKind")) + + // Set and update the finalizer on resource if r.reconciler + // implements Finalizer. + if resource, err = r.setFinalizerIfFinalizer(ctx, resource); err != nil { + logger.Warnw("Failed to set finalizers", zap.Error(err)) + } + + // Reconcile this copy of the resource and then write back any status + // updates regardless of whether the reconciliation errored out. + reconcileEvent = r.reconciler.ReconcileKind(ctx, resource) + } else if fin, ok := r.reconciler.(Finalizer); ok { + // Append the target method to the logger. + logger = logger.With(zap.String("targetMethod", "FinalizeKind")) + + // For finalizing reconcilers, if this resource being marked for deletion + // and reconciled cleanly (nil or normal event), remove the finalizer. + reconcileEvent = fin.FinalizeKind(ctx, resource) + if resource, err = r.clearFinalizer(ctx, resource, reconcileEvent); err != nil { + logger.Warnw("Failed to clear finalizers", zap.Error(err)) + } + } + + // Synchronize the status. + if equality.Semantic.DeepEqual(original.Status, resource.Status) { + // If we didn't change anything then don't call updateStatus. + // This is important because the copy we loaded from the injectionInformer's + // cache may be stale and we don't want to overwrite a prior update + // to status with this stale state. + } else if err = r.updateStatus(original, resource); err != nil { + logger.Warnw("Failed to update resource status", zap.Error(err)) + r.Recorder.Eventf(resource, v1.EventTypeWarning, "UpdateFailed", + "Failed to update status for %q: %v", resource.Name, err) + return err + } + + // Report the reconciler event, if any. + if reconcileEvent != nil { + var event *reconciler.ReconcilerEvent + if reconciler.EventAs(reconcileEvent, &event) { + logger.Infow("returned an event", zap.Any("event", reconcileEvent)) + r.Recorder.Eventf(resource, event.EventType, event.Reason, event.Format, event.Args...) + return nil + } else { + logger.Errorw("returned an error", zap.Error(reconcileEvent)) + r.Recorder.Event(resource, v1.EventTypeWarning, "InternalError", reconcileEvent.Error()) + return reconcileEvent + } + } + return nil +} + +func (r *reconcilerImpl) updateStatus(existing *v1alpha2.ContainerSource, desired *v1alpha2.ContainerSource) error { + existing = existing.DeepCopy() + return reconciler.RetryUpdateConflicts(func(attempts int) (err error) { + // The first iteration tries to use the injectionInformer's state, subsequent attempts fetch the latest state via API. + if attempts > 0 { + + getter := r.Client.SourcesV1alpha2().ContainerSources(desired.Namespace) + + existing, err = getter.Get(desired.Name, metav1.GetOptions{}) + if err != nil { + return err + } + } + + // If there's nothing to update, just return. + if reflect.DeepEqual(existing.Status, desired.Status) { + return nil + } + + existing.Status = desired.Status + + updater := r.Client.SourcesV1alpha2().ContainerSources(existing.Namespace) + + _, err = updater.UpdateStatus(existing) + return err + }) +} + +// updateFinalizersFiltered will update the Finalizers of the resource. +// TODO: this method could be generic and sync all finalizers. For now it only +// updates defaultFinalizerName. +func (r *reconcilerImpl) updateFinalizersFiltered(ctx context.Context, resource *v1alpha2.ContainerSource) (*v1alpha2.ContainerSource, error) { + finalizerName := defaultFinalizerName + + getter := r.Lister.ContainerSources(resource.Namespace) + + actual, err := getter.Get(resource.Name) + if err != nil { + return resource, err + } + + // Don't modify the informers copy. + existing := actual.DeepCopy() + + var finalizers []string + + // If there's nothing to update, just return. + existingFinalizers := sets.NewString(existing.Finalizers...) + desiredFinalizers := sets.NewString(resource.Finalizers...) + + if desiredFinalizers.Has(finalizerName) { + if existingFinalizers.Has(finalizerName) { + // Nothing to do. + return resource, nil + } + // Add the finalizer. + finalizers = append(existing.Finalizers, finalizerName) + } else { + if !existingFinalizers.Has(finalizerName) { + // Nothing to do. + return resource, nil + } + // Remove the finalizer. + existingFinalizers.Delete(finalizerName) + finalizers = existingFinalizers.List() + } + + mergePatch := map[string]interface{}{ + "metadata": map[string]interface{}{ + "finalizers": finalizers, + "resourceVersion": existing.ResourceVersion, + }, + } + + patch, err := json.Marshal(mergePatch) + if err != nil { + return resource, err + } + + patcher := r.Client.SourcesV1alpha2().ContainerSources(resource.Namespace) + + resource, err = patcher.Patch(resource.Name, types.MergePatchType, patch) + if err != nil { + r.Recorder.Eventf(resource, v1.EventTypeWarning, "FinalizerUpdateFailed", + "Failed to update finalizers for %q: %v", resource.Name, err) + } else { + r.Recorder.Eventf(resource, v1.EventTypeNormal, "FinalizerUpdate", + "Updated %q finalizers", resource.GetName()) + } + return resource, err +} + +func (r *reconcilerImpl) setFinalizerIfFinalizer(ctx context.Context, resource *v1alpha2.ContainerSource) (*v1alpha2.ContainerSource, error) { + if _, ok := r.reconciler.(Finalizer); !ok { + return resource, nil + } + + finalizers := sets.NewString(resource.Finalizers...) + + // If this resource is not being deleted, mark the finalizer. + if resource.GetDeletionTimestamp().IsZero() { + finalizers.Insert(defaultFinalizerName) + } + + resource.Finalizers = finalizers.List() + + // Synchronize the finalizers filtered by defaultFinalizerName. + return r.updateFinalizersFiltered(ctx, resource) +} + +func (r *reconcilerImpl) clearFinalizer(ctx context.Context, resource *v1alpha2.ContainerSource, reconcileEvent reconciler.Event) (*v1alpha2.ContainerSource, error) { + if _, ok := r.reconciler.(Finalizer); !ok { + return resource, nil + } + if resource.GetDeletionTimestamp().IsZero() { + return resource, nil + } + + finalizers := sets.NewString(resource.Finalizers...) + + if reconcileEvent != nil { + var event *reconciler.ReconcilerEvent + if reconciler.EventAs(reconcileEvent, &event) { + if event.EventType == v1.EventTypeNormal { + finalizers.Delete(defaultFinalizerName) + } + } + } else { + finalizers.Delete(defaultFinalizerName) + } + + resource.Finalizers = finalizers.List() + + // Synchronize the finalizers filtered by defaultFinalizerName. + return r.updateFinalizersFiltered(ctx, resource) +} diff --git a/pkg/client/injection/reconciler/sources/v1alpha2/containersource/stub/controller.go b/pkg/client/injection/reconciler/sources/v1alpha2/containersource/stub/controller.go new file mode 100644 index 00000000000..361c9cc9994 --- /dev/null +++ b/pkg/client/injection/reconciler/sources/v1alpha2/containersource/stub/controller.go @@ -0,0 +1,54 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package containersource + +import ( + context "context" + + containersource "knative.dev/eventing/pkg/client/injection/informers/sources/v1alpha2/containersource" + v1alpha2containersource "knative.dev/eventing/pkg/client/injection/reconciler/sources/v1alpha2/containersource" + configmap "knative.dev/pkg/configmap" + controller "knative.dev/pkg/controller" + logging "knative.dev/pkg/logging" +) + +// TODO: PLEASE COPY AND MODIFY THIS FILE AS A STARTING POINT + +// NewController creates a Reconciler for ContainerSource and returns the result of NewImpl. +func NewController( + ctx context.Context, + cmw configmap.Watcher, +) *controller.Impl { + logger := logging.FromContext(ctx) + + containersourceInformer := containersource.Get(ctx) + + // TODO: setup additional informers here. + + r := &Reconciler{} + impl := v1alpha2containersource.NewImpl(ctx, r) + + logger.Info("Setting up event handlers.") + + containersourceInformer.Informer().AddEventHandler(controller.HandleAll(impl.Enqueue)) + + // TODO: add additional informer event handlers here. + + return impl +} diff --git a/pkg/client/injection/reconciler/sources/v1alpha2/containersource/stub/reconciler.go b/pkg/client/injection/reconciler/sources/v1alpha2/containersource/stub/reconciler.go new file mode 100644 index 00000000000..6a5b038f11e --- /dev/null +++ b/pkg/client/injection/reconciler/sources/v1alpha2/containersource/stub/reconciler.go @@ -0,0 +1,66 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package containersource + +import ( + context "context" + + v1 "k8s.io/api/core/v1" + v1alpha2 "knative.dev/eventing/pkg/apis/sources/v1alpha2" + containersource "knative.dev/eventing/pkg/client/injection/reconciler/sources/v1alpha2/containersource" + reconciler "knative.dev/pkg/reconciler" +) + +// TODO: PLEASE COPY AND MODIFY THIS FILE AS A STARTING POINT + +// newReconciledNormal makes a new reconciler event with event type Normal, and +// reason ContainerSourceReconciled. +func newReconciledNormal(namespace, name string) reconciler.Event { + return reconciler.NewEvent(v1.EventTypeNormal, "ContainerSourceReconciled", "ContainerSource reconciled: \"%s/%s\"", namespace, name) +} + +// Reconciler implements controller.Reconciler for ContainerSource resources. +type Reconciler struct { + // TODO: add additional requirements here. +} + +// Check that our Reconciler implements Interface +var _ containersource.Interface = (*Reconciler)(nil) + +// Optionally check that our Reconciler implements Finalizer +//var _ containersource.Finalizer = (*Reconciler)(nil) + +// ReconcileKind implements Interface.ReconcileKind. +func (r *Reconciler) ReconcileKind(ctx context.Context, o *v1alpha2.ContainerSource) reconciler.Event { + // TODO: use this if the resource implements InitializeConditions. + // o.Status.InitializeConditions() + + // TODO: add custom reconciliation logic here. + + // TODO: use this if the object has .status.ObservedGeneration. + // o.Status.ObservedGeneration = o.Generation + return newReconciledNormal(o.Namespace, o.Name) +} + +// Optionally, use FinalizeKind to add finalizers. FinalizeKind will be called +// when the resource is deleted. +//func (r *Reconciler) FinalizeKind(ctx context.Context, o *v1alpha2.ContainerSource) reconciler.Event { +// // TODO: add custom finalization logic here. +// return nil +//} diff --git a/pkg/client/listers/sources/v1alpha2/containersource.go b/pkg/client/listers/sources/v1alpha2/containersource.go new file mode 100644 index 00000000000..df3ef811429 --- /dev/null +++ b/pkg/client/listers/sources/v1alpha2/containersource.go @@ -0,0 +1,94 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha2 + +import ( + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" + v1alpha2 "knative.dev/eventing/pkg/apis/sources/v1alpha2" +) + +// ContainerSourceLister helps list ContainerSources. +type ContainerSourceLister interface { + // List lists all ContainerSources in the indexer. + List(selector labels.Selector) (ret []*v1alpha2.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 []*v1alpha2.ContainerSource, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha2.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 []*v1alpha2.ContainerSource, err error) + // Get retrieves the ContainerSource from the indexer for a given namespace and name. + Get(name string) (*v1alpha2.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 []*v1alpha2.ContainerSource, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha2.ContainerSource)) + }) + return ret, err +} + +// Get retrieves the ContainerSource from the indexer for a given namespace and name. +func (s containerSourceNamespaceLister) Get(name string) (*v1alpha2.ContainerSource, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1alpha2.Resource("containersource"), name) + } + return obj.(*v1alpha2.ContainerSource), nil +} diff --git a/pkg/client/listers/sources/v1alpha2/expansion_generated.go b/pkg/client/listers/sources/v1alpha2/expansion_generated.go index 59db08d0ca1..41255a85f69 100644 --- a/pkg/client/listers/sources/v1alpha2/expansion_generated.go +++ b/pkg/client/listers/sources/v1alpha2/expansion_generated.go @@ -26,6 +26,14 @@ type ApiServerSourceListerExpansion interface{} // ApiServerSourceNamespaceLister. type ApiServerSourceNamespaceListerExpansion interface{} +// ContainerSourceListerExpansion allows custom methods to be added to +// ContainerSourceLister. +type ContainerSourceListerExpansion interface{} + +// ContainerSourceNamespaceListerExpansion allows custom methods to be added to +// ContainerSourceNamespaceLister. +type ContainerSourceNamespaceListerExpansion interface{} + // PingSourceListerExpansion allows custom methods to be added to // PingSourceLister. type PingSourceListerExpansion interface{} From 1dcc6415e2654cdfa2d7cd2b460de32674ae5f05 Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Thu, 26 Mar 2020 14:40:52 -0700 Subject: [PATCH 10/16] moving to v1alpha2 --- .../sources/v1alpha1/container_defaults.go | 42 --- .../v1alpha1/container_defaults_test.go | 115 ------ .../sources/v1alpha1/container_lifecycle.go | 92 ----- .../v1alpha1/container_lifecycle_test.go | 311 ---------------- pkg/apis/sources/v1alpha1/container_types.go | 92 ----- .../sources/v1alpha1/container_validation.go | 59 --- .../v1alpha1/container_validation_test.go | 112 ------ pkg/apis/sources/v1alpha1/register.go | 2 - pkg/apis/sources/v1alpha1/register_test.go | 2 + .../typed/sources/v1alpha1/containersource.go | 191 ---------- .../v1alpha1/fake/fake_containersource.go | 140 -------- .../sources/v1alpha1/containersource.go | 89 ----- .../containersource/containersource.go | 52 --- .../v1alpha1/containersource/fake/fake.go | 40 --- .../v1alpha1/containersource/controller.go | 97 ----- .../v1alpha1/containersource/reconciler.go | 339 ------------------ .../containersource/stub/controller.go | 54 --- .../containersource/stub/reconciler.go | 66 ---- .../sources/v1alpha1/containersource.go | 94 ----- .../containersource/containersource.go | 14 +- .../containersource/containersource_test.go | 24 +- pkg/reconciler/containersource/controller.go | 14 +- .../containersource/controller_test.go | 4 +- .../containersource/resources/sinkbinding.go | 8 +- pkg/reconciler/testing/containersource.go | 32 +- pkg/reconciler/testing/listers.go | 12 +- 26 files changed, 57 insertions(+), 2040 deletions(-) delete mode 100644 pkg/apis/sources/v1alpha1/container_defaults.go delete mode 100644 pkg/apis/sources/v1alpha1/container_defaults_test.go delete mode 100644 pkg/apis/sources/v1alpha1/container_lifecycle.go delete mode 100644 pkg/apis/sources/v1alpha1/container_lifecycle_test.go delete mode 100644 pkg/apis/sources/v1alpha1/container_types.go delete mode 100644 pkg/apis/sources/v1alpha1/container_validation.go delete mode 100644 pkg/apis/sources/v1alpha1/container_validation_test.go delete mode 100644 pkg/client/clientset/versioned/typed/sources/v1alpha1/containersource.go delete mode 100644 pkg/client/clientset/versioned/typed/sources/v1alpha1/fake/fake_containersource.go delete mode 100644 pkg/client/informers/externalversions/sources/v1alpha1/containersource.go delete mode 100644 pkg/client/injection/informers/sources/v1alpha1/containersource/containersource.go delete mode 100644 pkg/client/injection/informers/sources/v1alpha1/containersource/fake/fake.go delete mode 100644 pkg/client/injection/reconciler/sources/v1alpha1/containersource/controller.go delete mode 100644 pkg/client/injection/reconciler/sources/v1alpha1/containersource/reconciler.go delete mode 100644 pkg/client/injection/reconciler/sources/v1alpha1/containersource/stub/controller.go delete mode 100644 pkg/client/injection/reconciler/sources/v1alpha1/containersource/stub/reconciler.go delete mode 100644 pkg/client/listers/sources/v1alpha1/containersource.go diff --git a/pkg/apis/sources/v1alpha1/container_defaults.go b/pkg/apis/sources/v1alpha1/container_defaults.go deleted file mode 100644 index ee52e33b4b5..00000000000 --- a/pkg/apis/sources/v1alpha1/container_defaults.go +++ /dev/null @@ -1,42 +0,0 @@ -/* -Copyright 2020 The Knative Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package v1alpha1 - -import ( - "context" - "fmt" - - corev1 "k8s.io/api/core/v1" - "knative.dev/pkg/apis" -) - -func (s *ContainerSource) SetDefaults(ctx context.Context) { - withName := apis.WithinParent(ctx, s.ObjectMeta) - s.Spec.SetDefaults(withName) -} - -func (ss *ContainerSourceSpec) SetDefaults(ctx context.Context) { - containers := make([]corev1.Container, 0, len(ss.Template.Spec.Containers)) - for i, c := range ss.Template.Spec.Containers { - // If the Container specified has no name, then default to "_". - if c.Name == "" { - c.Name = fmt.Sprintf("%s-%d", apis.ParentMeta(ctx).Name, i) - } - containers = append(containers, c) - } - ss.Template.Spec.Containers = containers -} diff --git a/pkg/apis/sources/v1alpha1/container_defaults_test.go b/pkg/apis/sources/v1alpha1/container_defaults_test.go deleted file mode 100644 index 701080b0423..00000000000 --- a/pkg/apis/sources/v1alpha1/container_defaults_test.go +++ /dev/null @@ -1,115 +0,0 @@ -/* -Copyright 2020 The Knative Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package v1alpha1 - -import ( - "context" - "testing" - - "github.com/google/go-cmp/cmp" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// No-op test because method does nothing. -func TestContainerSourceDefaults(t *testing.T) { - testCases := map[string]struct { - initial ContainerSource - expected ContainerSource - }{ - "no container name": { - initial: ContainerSource{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-name", - Namespace: "test-namespace", - }, - Spec: ContainerSourceSpec{ - Template: corev1.PodTemplateSpec{ - Spec: corev1.PodSpec{ - Containers: []corev1.Container{{ - Image: "test-image", - }}, - }, - }, - }, - }, - expected: ContainerSource{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-name", - Namespace: "test-namespace", - }, - Spec: ContainerSourceSpec{ - Template: corev1.PodTemplateSpec{ - Spec: corev1.PodSpec{ - Containers: []corev1.Container{{ - Name: "test-name-0", - Image: "test-image", - }}, - }, - }, - }, - }, - }, - "one with ontainer name one without": { - initial: ContainerSource{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-name", - Namespace: "test-namespace", - }, - Spec: ContainerSourceSpec{ - Template: corev1.PodTemplateSpec{ - Spec: corev1.PodSpec{ - Containers: []corev1.Container{{ - Name: "test-container", - Image: "test-image", - }, { - Image: "test-another-image", - }}, - }, - }, - }, - }, - expected: ContainerSource{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-name", - Namespace: "test-namespace", - }, - Spec: ContainerSourceSpec{ - Template: corev1.PodTemplateSpec{ - Spec: corev1.PodSpec{ - Containers: []corev1.Container{{ - Name: "test-container", - Image: "test-image", - }, { - Name: "test-name-1", - Image: "test-another-image", - }}, - }, - }, - }, - }, - }, - } - for n, tc := range testCases { - t.Run(n, func(t *testing.T) { - tc.initial.SetDefaults(context.Background()) - if diff := cmp.Diff(tc.expected, tc.initial); diff != "" { - t.Fatalf("Unexpected defaults (-want, +got): %s", diff) - } - }) - } -} diff --git a/pkg/apis/sources/v1alpha1/container_lifecycle.go b/pkg/apis/sources/v1alpha1/container_lifecycle.go deleted file mode 100644 index 16964e0d98c..00000000000 --- a/pkg/apis/sources/v1alpha1/container_lifecycle.go +++ /dev/null @@ -1,92 +0,0 @@ -/* -Copyright 2020 The Knative Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package v1alpha1 - -import ( - appsv1 "k8s.io/api/apps/v1" - corev1 "k8s.io/api/core/v1" - "knative.dev/eventing/pkg/apis/duck" - "knative.dev/pkg/apis" -) - -const ( - // ContainerSourceConditionReady has status True when the ContainerSource is ready to send events. - ContainerSourceConditionReady = apis.ConditionReady - - // ContainerSourceConditionSinkBindingReady has status True when the ContainerSource's SinkBinding is ready. - ContainerSourceConditionSinkBindingReady apis.ConditionType = "SinkBindingReady" - - // ContainerSourceConditionReceiveAdapterReady has status True when the ContainerSource's ReceiveAdapter is ready. - ContainerSourceConditionReceiveAdapterReady apis.ConditionType = "ReceiveAdapterReady" -) - -var containerCondSet = apis.NewLivingConditionSet( - ContainerSourceConditionSinkBindingReady, - ContainerSourceConditionReceiveAdapterReady, -) - -// GetCondition returns the condition currently associated with the given type, or nil. -func (s *ContainerSourceStatus) GetCondition(t apis.ConditionType) *apis.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() -} - -// PropagateSinkBindingStatus uses the availability of the provided Deployment to determine if -// ContainerSourceConditionSinkBindingReady should be marked as true, false or unknown. -func (s *ContainerSourceStatus) PropagateSinkBindingStatus(status *SinkBindingStatus) { - // Do not copy conditions nor observedGeneration - conditions := s.Conditions - observedGeneration := s.ObservedGeneration - s.SourceStatus = status.SourceStatus - s.Conditions = conditions - s.ObservedGeneration = observedGeneration - - cond := status.GetCondition(apis.ConditionReady) - switch { - case cond == nil: - containerCondSet.Manage(s).MarkUnknown(ContainerSourceConditionSinkBindingReady, "", "") - case cond.Status == corev1.ConditionTrue: - containerCondSet.Manage(s).MarkTrue(ContainerSourceConditionSinkBindingReady) - case cond.Status == corev1.ConditionFalse: - containerCondSet.Manage(s).MarkFalse(ContainerSourceConditionSinkBindingReady, cond.Reason, cond.Message) - case cond.Status == corev1.ConditionUnknown: - containerCondSet.Manage(s).MarkUnknown(ContainerSourceConditionSinkBindingReady, cond.Reason, cond.Message) - default: - containerCondSet.Manage(s).MarkUnknown(ContainerSourceConditionSinkBindingReady, cond.Reason, cond.Message) - } -} - -// PropagateReceiveAdapterStatus uses the availability of the provided Deployment to determine if -// ContainerSourceConditionReceiveAdapterReady should be marked as true or false. -func (s *ContainerSourceStatus) PropagateReceiveAdapterStatus(d *appsv1.Deployment) { - if duck.DeploymentIsAvailable(&d.Status, false) { - containerCondSet.Manage(s).MarkTrue(ContainerSourceConditionReceiveAdapterReady) - } else { - // I don't know how to propagate the status well, so just give the name of the Deployment - // for now. - containerCondSet.Manage(s).MarkFalse(ContainerSourceConditionReceiveAdapterReady, "DeploymentUnavailable", "The Deployment '%s' is unavailable.", d.Name) - } -} diff --git a/pkg/apis/sources/v1alpha1/container_lifecycle_test.go b/pkg/apis/sources/v1alpha1/container_lifecycle_test.go deleted file mode 100644 index 8b96039d8d3..00000000000 --- a/pkg/apis/sources/v1alpha1/container_lifecycle_test.go +++ /dev/null @@ -1,311 +0,0 @@ -/* -Copyright 2020 The Knative Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package v1alpha1 - -import ( - "testing" - - "github.com/google/go-cmp/cmp/cmpopts" - - "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" - "knative.dev/pkg/apis" - duckv1 "knative.dev/pkg/apis/duck/v1" -) - -var ( - availDeployment = &appsv1.Deployment{ - Status: appsv1.DeploymentStatus{ - Conditions: []appsv1.DeploymentCondition{ - { - Type: appsv1.DeploymentAvailable, - Status: corev1.ConditionTrue, - }, - }, - }, - } - unavailDeployment = &appsv1.Deployment{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-name", - Namespace: "test-namespace", - }, - Status: appsv1.DeploymentStatus{ - Conditions: []appsv1.DeploymentCondition{ - { - Type: appsv1.DeploymentAvailable, - Status: corev1.ConditionFalse, - }, - }, - }, - } - - readySinkBinding = &SinkBinding{ - Status: SinkBindingStatus{ - SourceStatus: duckv1.SourceStatus{ - Status: duckv1.Status{ - Conditions: []apis.Condition{{ - Type: apis.ConditionReady, - Status: corev1.ConditionTrue, - }}, - }, - }, - }, - } - - notReadySinkBinding = &SinkBinding{ - Status: SinkBindingStatus{ - SourceStatus: duckv1.SourceStatus{ - Status: duckv1.Status{ - Conditions: []apis.Condition{{ - Type: apis.ConditionReady, - Status: corev1.ConditionFalse, - Reason: "Testing", - Message: "hi", - }}, - }, - }, - }, - } -) - -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 ready ra", - s: func() *ContainerSourceStatus { - s := &ContainerSourceStatus{} - s.InitializeConditions() - s.PropagateReceiveAdapterStatus(availDeployment) - return s - }(), - want: false, - }, { - name: "mark ready sb", - s: func() *ContainerSourceStatus { - s := &ContainerSourceStatus{} - s.InitializeConditions() - s.PropagateSinkBindingStatus(&readySinkBinding.Status) - return s - }(), - want: false, - }, { - name: "mark ready sb and ra", - s: func() *ContainerSourceStatus { - s := &ContainerSourceStatus{} - s.InitializeConditions() - s.PropagateSinkBindingStatus(&readySinkBinding.Status) - s.PropagateReceiveAdapterStatus(availDeployment) - return s - }(), - want: true, - }, { - name: "mark ready sb and ra the no sb", - s: func() *ContainerSourceStatus { - s := &ContainerSourceStatus{} - s.InitializeConditions() - s.PropagateSinkBindingStatus(&readySinkBinding.Status) - s.PropagateReceiveAdapterStatus(availDeployment) - s.PropagateSinkBindingStatus(¬ReadySinkBinding.Status) - return s - }(), - want: false, - }, { - name: "mark ready sb and ra then not ra", - s: func() *ContainerSourceStatus { - s := &ContainerSourceStatus{} - s.InitializeConditions() - s.PropagateReceiveAdapterStatus(availDeployment) - s.PropagateSinkBindingStatus(¬ReadySinkBinding.Status) - s.PropagateReceiveAdapterStatus(unavailDeployment) - return s - }(), - want: false, - }, { - name: "mark not ready sb and ready ra", - s: func() *ContainerSourceStatus { - s := &ContainerSourceStatus{} - s.InitializeConditions() - s.PropagateSinkBindingStatus(¬ReadySinkBinding.Status) - s.PropagateReceiveAdapterStatus(availDeployment) - return s - }(), - want: false, - }, { - name: "mark not ready sb and ra then ready sb", - s: func() *ContainerSourceStatus { - s := &ContainerSourceStatus{} - s.InitializeConditions() - s.PropagateSinkBindingStatus(¬ReadySinkBinding.Status) - s.PropagateReceiveAdapterStatus(availDeployment) - s.PropagateSinkBindingStatus(&readySinkBinding.Status) - 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 apis.ConditionType - want *apis.Condition - }{{ - name: "uninitialized", - s: &ContainerSourceStatus{}, - condQuery: ContainerSourceConditionReady, - want: nil, - }, { - name: "initialized", - s: func() *ContainerSourceStatus { - s := &ContainerSourceStatus{} - s.InitializeConditions() - return s - }(), - condQuery: ContainerSourceConditionReady, - want: &apis.Condition{ - Type: ContainerSourceConditionReady, - Status: corev1.ConditionUnknown, - }, - }, { - name: "mark ready ra", - s: func() *ContainerSourceStatus { - s := &ContainerSourceStatus{} - s.InitializeConditions() - s.PropagateReceiveAdapterStatus(availDeployment) - return s - }(), - condQuery: ContainerSourceConditionReady, - want: &apis.Condition{ - Type: ContainerSourceConditionReady, - Status: corev1.ConditionUnknown, - }, - }, { - name: "mark ready sb", - s: func() *ContainerSourceStatus { - s := &ContainerSourceStatus{} - s.InitializeConditions() - s.PropagateSinkBindingStatus(&readySinkBinding.Status) - return s - }(), - condQuery: ContainerSourceConditionReady, - want: &apis.Condition{ - Type: ContainerSourceConditionReady, - Status: corev1.ConditionUnknown, - }, - }, { - name: "mark ready sb and ra", - s: func() *ContainerSourceStatus { - s := &ContainerSourceStatus{} - s.InitializeConditions() - s.PropagateSinkBindingStatus(&readySinkBinding.Status) - s.PropagateReceiveAdapterStatus(availDeployment) - return s - }(), - condQuery: ContainerSourceConditionReady, - want: &apis.Condition{ - Type: ContainerSourceConditionReady, - Status: corev1.ConditionTrue, - }, - }, { - name: "mark ready sb and ra then no sb", - s: func() *ContainerSourceStatus { - s := &ContainerSourceStatus{} - s.InitializeConditions() - s.PropagateSinkBindingStatus(&readySinkBinding.Status) - s.PropagateReceiveAdapterStatus(availDeployment) - s.PropagateSinkBindingStatus(¬ReadySinkBinding.Status) - return s - }(), - condQuery: ContainerSourceConditionReady, - want: &apis.Condition{ - Type: ContainerSourceConditionReady, - Status: corev1.ConditionFalse, - Reason: "Testing", - Message: "hi", - }, - }, { - name: "mark ready sb and ra then no ra", - s: func() *ContainerSourceStatus { - s := &ContainerSourceStatus{} - s.InitializeConditions() - s.PropagateSinkBindingStatus(&readySinkBinding.Status) - s.PropagateReceiveAdapterStatus(availDeployment) - s.PropagateReceiveAdapterStatus(unavailDeployment) - return s - }(), - condQuery: ContainerSourceConditionReady, - want: &apis.Condition{ - Type: ContainerSourceConditionReady, - Status: corev1.ConditionFalse, - Reason: "DeploymentUnavailable", - Message: "The Deployment 'test-name' is unavailable.", - }, - }, { - name: "mark not ready sb and ready ra then ready sb", - s: func() *ContainerSourceStatus { - s := &ContainerSourceStatus{} - s.InitializeConditions() - s.PropagateSinkBindingStatus(¬ReadySinkBinding.Status) - s.PropagateReceiveAdapterStatus(availDeployment) - s.PropagateSinkBindingStatus(&readySinkBinding.Status) - return s - }(), - condQuery: ContainerSourceConditionReady, - want: &apis.Condition{ - Type: ContainerSourceConditionReady, - Status: corev1.ConditionTrue, - }, - }} - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - got := test.s.GetCondition(test.condQuery) - ignoreTime := cmpopts.IgnoreFields(apis.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/container_types.go b/pkg/apis/sources/v1alpha1/container_types.go deleted file mode 100644 index ce6fe9eabdf..00000000000 --- a/pkg/apis/sources/v1alpha1/container_types.go +++ /dev/null @@ -1,92 +0,0 @@ -/* -Copyright 2020 The Knative Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package v1alpha1 - -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" - "knative.dev/pkg/apis" - duckv1 "knative.dev/pkg/apis/duck/v1" - "knative.dev/pkg/kmeta" -) - -// +genclient -// +genreconciler -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -// 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"` -} - -var ( - _ runtime.Object = (*ContainerSource)(nil) - _ kmeta.OwnerRefable = (*ContainerSource)(nil) - _ apis.Validatable = (*ContainerSource)(nil) - _ apis.Defaultable = (*ContainerSource)(nil) - _ apis.HasSpec = (*ContainerSource)(nil) -) - -// ContainerSourceSpec defines the desired state of ContainerSource -type ContainerSourceSpec struct { - // inherits duck/v1 SourceSpec, which currently provides: - // * Sink - a reference to an object that will resolve to a domain name or - // a URI directly to use as the sink. - // * CloudEventOverrides - defines overrides to control the output format - // and modifications of the event sent to the sink. - duckv1.SourceSpec `json:",inline"` - - // Template describes the pods that will be created - Template corev1.PodTemplateSpec `json:"template"` -} - -// 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/v1 SourceStatus, 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. - // * SinkURI - the current active sink URI that has been configured for the - // Source. - duckv1.SourceStatus `json:",inline"` -} - -// +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"` -} - -// GetUntypedSpec returns the spec of the ContainerSource. -func (c *ContainerSource) GetUntypedSpec() interface{} { - return c.Spec -} diff --git a/pkg/apis/sources/v1alpha1/container_validation.go b/pkg/apis/sources/v1alpha1/container_validation.go deleted file mode 100644 index cd1960cdde3..00000000000 --- a/pkg/apis/sources/v1alpha1/container_validation.go +++ /dev/null @@ -1,59 +0,0 @@ -/* -Copyright 2020 The Knative Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package v1alpha1 - -import ( - "context" - - corev1 "k8s.io/api/core/v1" - "knative.dev/pkg/apis" -) - -func (c *ContainerSource) Validate(ctx context.Context) *apis.FieldError { - return c.Spec.Validate(ctx).ViaField("spec") -} - -func (cs *ContainerSourceSpec) Validate(ctx context.Context) *apis.FieldError { - var errs *apis.FieldError - if fe := cs.Sink.Validate(ctx); fe != nil { - errs = errs.Also(fe.ViaField("sink")) - } - - // Validate there is at least a container - if cs.Template.Spec.Containers == nil || len(cs.Template.Spec.Containers) == 0 { - fe := apis.ErrMissingField("containers") - errs = errs.Also(fe) - } else { - for i, c := range cs.Template.Spec.Containers { - if ce := isValidContainer(&c); ce != nil { - errs = errs.Also(ce.ViaFieldIndex("containers", i)) - } - } - } - return errs -} - -func isValidContainer(c *corev1.Container) *apis.FieldError { - var errs *apis.FieldError - if c.Name == "" { - errs = errs.Also(apis.ErrMissingField("name")) - } - if c.Image == "" { - errs = errs.Also(apis.ErrMissingField("image")) - } - return errs -} diff --git a/pkg/apis/sources/v1alpha1/container_validation_test.go b/pkg/apis/sources/v1alpha1/container_validation_test.go deleted file mode 100644 index e64df8eca28..00000000000 --- a/pkg/apis/sources/v1alpha1/container_validation_test.go +++ /dev/null @@ -1,112 +0,0 @@ -/* -Copyright 2020 The Knative Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package v1alpha1 - -import ( - "context" - "testing" - - "github.com/google/go-cmp/cmp" - corev1 "k8s.io/api/core/v1" - "knative.dev/pkg/apis" - duckv1 "knative.dev/pkg/apis/duck/v1" -) - -func TestContainerSourceValidation(t *testing.T) { - tests := []struct { - name string - spec ContainerSourceSpec - want *apis.FieldError - }{{ - name: "missing container", - spec: ContainerSourceSpec{ - Template: corev1.PodTemplateSpec{}, - SourceSpec: duckv1.SourceSpec{ - Sink: duckv1.Destination{ - Ref: &duckv1.KReference{ - APIVersion: "v1alpha1", - Kind: "Broker", - Name: "default", - }, - }, - }, - }, - want: func() *apis.FieldError { - var errs *apis.FieldError - fe := apis.ErrMissingField("containers") - errs = errs.Also(fe) - return errs - }(), - }, { - name: "missing container image", - spec: ContainerSourceSpec{ - Template: corev1.PodTemplateSpec{ - Spec: corev1.PodSpec{ - Containers: []corev1.Container{{ - Name: "test-name", - }}, - }, - }, - SourceSpec: duckv1.SourceSpec{ - Sink: duckv1.Destination{ - Ref: &duckv1.KReference{ - APIVersion: "eventing.knative.dev/v1alpha1", - Kind: "Broker", - Name: "default", - }, - }, - }, - }, - want: func() *apis.FieldError { - var errs *apis.FieldError - fe := apis.ErrMissingField("containers[0].image") - errs = errs.Also(fe) - return errs - }(), - }, { - name: "empty sink", - spec: ContainerSourceSpec{ - Template: corev1.PodTemplateSpec{ - Spec: corev1.PodSpec{ - Containers: []corev1.Container{{ - Name: "name", - Image: "image", - }}, - }, - }, - SourceSpec: duckv1.SourceSpec{ - Sink: duckv1.Destination{}, - }, - }, - want: func() *apis.FieldError { - var errs *apis.FieldError - fe := apis.ErrGeneric("expected at least one, got none", "sink.ref", "sink.uri") - errs = errs.Also(fe) - return errs - }(), - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - got := test.spec.Validate(context.TODO()) - if diff := cmp.Diff(test.want.Error(), got.Error()); diff != "" { - t.Errorf("ContainerSourceSpec.Validate (-want, +got) = %v", diff) - } - }) - } -} diff --git a/pkg/apis/sources/v1alpha1/register.go b/pkg/apis/sources/v1alpha1/register.go index 9809733a80f..23aafaf34d2 100644 --- a/pkg/apis/sources/v1alpha1/register.go +++ b/pkg/apis/sources/v1alpha1/register.go @@ -51,8 +51,6 @@ func addKnownTypes(scheme *runtime.Scheme) error { &PingSourceList{}, &SinkBinding{}, &SinkBindingList{}, - &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 232d5339973..f468d44152f 100644 --- a/pkg/apis/sources/v1alpha1/register_test.go +++ b/pkg/apis/sources/v1alpha1/register_test.go @@ -64,6 +64,8 @@ func TestKnownTypes(t *testing.T) { "ApiServerSourceList", "SinkBinding", "SinkBindingList", + "PingSource", + "PingSourceList", } { if _, ok := types[name]; !ok { t.Errorf("Did not find %q as registered type", name) diff --git a/pkg/client/clientset/versioned/typed/sources/v1alpha1/containersource.go b/pkg/client/clientset/versioned/typed/sources/v1alpha1/containersource.go deleted file mode 100644 index b26c50137a9..00000000000 --- a/pkg/client/clientset/versioned/typed/sources/v1alpha1/containersource.go +++ /dev/null @@ -1,191 +0,0 @@ -/* -Copyright 2020 The Knative Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - "time" - - 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" - v1alpha1 "knative.dev/eventing/pkg/apis/sources/v1alpha1" - scheme "knative.dev/eventing/pkg/client/clientset/versioned/scheme" -) - -// 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) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - result = &v1alpha1.ContainerSourceList{} - err = c.client.Get(). - Namespace(c.ns). - Resource("containersources"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Do(). - Into(result) - return -} - -// Watch returns a watch.Interface that watches the requested containerSources. -func (c *containerSources) Watch(opts v1.ListOptions) (watch.Interface, error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - opts.Watch = true - return c.client.Get(). - Namespace(c.ns). - Resource("containersources"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - 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 { - var timeout time.Duration - if listOptions.TimeoutSeconds != nil { - timeout = time.Duration(*listOptions.TimeoutSeconds) * time.Second - } - return c.client.Delete(). - Namespace(c.ns). - Resource("containersources"). - VersionedParams(&listOptions, scheme.ParameterCodec). - Timeout(timeout). - 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 deleted file mode 100644 index c7701ae9430..00000000000 --- a/pkg/client/clientset/versioned/typed/sources/v1alpha1/fake/fake_containersource.go +++ /dev/null @@ -1,140 +0,0 @@ -/* -Copyright 2020 The Knative Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -package fake - -import ( - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - labels "k8s.io/apimachinery/pkg/labels" - schema "k8s.io/apimachinery/pkg/runtime/schema" - types "k8s.io/apimachinery/pkg/types" - watch "k8s.io/apimachinery/pkg/watch" - testing "k8s.io/client-go/testing" - v1alpha1 "knative.dev/eventing/pkg/apis/sources/v1alpha1" -) - -// FakeContainerSources implements ContainerSourceInterface -type FakeContainerSources struct { - Fake *FakeSourcesV1alpha1 - ns string -} - -var containersourcesResource = schema.GroupVersionResource{Group: "sources.knative.dev", Version: "v1alpha1", Resource: "containersources"} - -var containersourcesKind = schema.GroupVersionKind{Group: "sources.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, pt, data, subresources...), &v1alpha1.ContainerSource{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha1.ContainerSource), err -} diff --git a/pkg/client/informers/externalversions/sources/v1alpha1/containersource.go b/pkg/client/informers/externalversions/sources/v1alpha1/containersource.go deleted file mode 100644 index 79660d1a416..00000000000 --- a/pkg/client/informers/externalversions/sources/v1alpha1/containersource.go +++ /dev/null @@ -1,89 +0,0 @@ -/* -Copyright 2020 The Knative Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by informer-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - time "time" - - 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" - sourcesv1alpha1 "knative.dev/eventing/pkg/apis/sources/v1alpha1" - versioned "knative.dev/eventing/pkg/client/clientset/versioned" - internalinterfaces "knative.dev/eventing/pkg/client/informers/externalversions/internalinterfaces" - v1alpha1 "knative.dev/eventing/pkg/client/listers/sources/v1alpha1" -) - -// 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/injection/informers/sources/v1alpha1/containersource/containersource.go b/pkg/client/injection/informers/sources/v1alpha1/containersource/containersource.go deleted file mode 100644 index 11b5cc737a7..00000000000 --- a/pkg/client/injection/informers/sources/v1alpha1/containersource/containersource.go +++ /dev/null @@ -1,52 +0,0 @@ -/* -Copyright 2020 The Knative Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by injection-gen. DO NOT EDIT. - -package containersource - -import ( - context "context" - - v1alpha1 "knative.dev/eventing/pkg/client/informers/externalversions/sources/v1alpha1" - factory "knative.dev/eventing/pkg/client/injection/informers/factory" - controller "knative.dev/pkg/controller" - injection "knative.dev/pkg/injection" - logging "knative.dev/pkg/logging" -) - -func init() { - injection.Default.RegisterInformer(withInformer) -} - -// Key is used for associating the Informer inside the context.Context. -type Key struct{} - -func withInformer(ctx context.Context) (context.Context, controller.Informer) { - f := factory.Get(ctx) - inf := f.Sources().V1alpha1().ContainerSources() - return context.WithValue(ctx, Key{}, inf), inf.Informer() -} - -// Get extracts the typed informer from the context. -func Get(ctx context.Context) v1alpha1.ContainerSourceInformer { - untyped := ctx.Value(Key{}) - if untyped == nil { - logging.FromContext(ctx).Panic( - "Unable to fetch knative.dev/eventing/pkg/client/informers/externalversions/sources/v1alpha1.ContainerSourceInformer from context.") - } - return untyped.(v1alpha1.ContainerSourceInformer) -} diff --git a/pkg/client/injection/informers/sources/v1alpha1/containersource/fake/fake.go b/pkg/client/injection/informers/sources/v1alpha1/containersource/fake/fake.go deleted file mode 100644 index 8a8f20d6848..00000000000 --- a/pkg/client/injection/informers/sources/v1alpha1/containersource/fake/fake.go +++ /dev/null @@ -1,40 +0,0 @@ -/* -Copyright 2020 The Knative Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by injection-gen. DO NOT EDIT. - -package fake - -import ( - context "context" - - fake "knative.dev/eventing/pkg/client/injection/informers/factory/fake" - containersource "knative.dev/eventing/pkg/client/injection/informers/sources/v1alpha1/containersource" - controller "knative.dev/pkg/controller" - injection "knative.dev/pkg/injection" -) - -var Get = containersource.Get - -func init() { - injection.Fake.RegisterInformer(withInformer) -} - -func withInformer(ctx context.Context) (context.Context, controller.Informer) { - f := fake.Get(ctx) - inf := f.Sources().V1alpha1().ContainerSources() - return context.WithValue(ctx, containersource.Key{}, inf), inf.Informer() -} diff --git a/pkg/client/injection/reconciler/sources/v1alpha1/containersource/controller.go b/pkg/client/injection/reconciler/sources/v1alpha1/containersource/controller.go deleted file mode 100644 index abfd2637daf..00000000000 --- a/pkg/client/injection/reconciler/sources/v1alpha1/containersource/controller.go +++ /dev/null @@ -1,97 +0,0 @@ -/* -Copyright 2020 The Knative Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by injection-gen. DO NOT EDIT. - -package containersource - -import ( - context "context" - - corev1 "k8s.io/api/core/v1" - watch "k8s.io/apimachinery/pkg/watch" - scheme "k8s.io/client-go/kubernetes/scheme" - v1 "k8s.io/client-go/kubernetes/typed/core/v1" - record "k8s.io/client-go/tools/record" - versionedscheme "knative.dev/eventing/pkg/client/clientset/versioned/scheme" - injectionclient "knative.dev/eventing/pkg/client/injection/client" - containersource "knative.dev/eventing/pkg/client/injection/informers/sources/v1alpha1/containersource" - client "knative.dev/pkg/client/injection/kube/client" - controller "knative.dev/pkg/controller" - logging "knative.dev/pkg/logging" -) - -const ( - defaultControllerAgentName = "containersource-controller" - defaultFinalizerName = "containersources.sources.knative.dev" - defaultQueueName = "containersources" -) - -// NewImpl returns a controller.Impl that handles queuing and feeding work from -// the queue through an implementation of controller.Reconciler, delegating to -// the provided Interface and optional Finalizer methods. OptionsFn is used to return -// controller.Options to be used but the internal reconciler. -func NewImpl(ctx context.Context, r Interface, optionsFns ...controller.OptionsFn) *controller.Impl { - logger := logging.FromContext(ctx) - - // Check the options function input. It should be 0 or 1. - if len(optionsFns) > 1 { - logger.Fatalf("up to one options function is supported, found %d", len(optionsFns)) - } - - containersourceInformer := containersource.Get(ctx) - - recorder := controller.GetEventRecorder(ctx) - if recorder == nil { - // Create event broadcaster - logger.Debug("Creating event broadcaster") - eventBroadcaster := record.NewBroadcaster() - watches := []watch.Interface{ - eventBroadcaster.StartLogging(logger.Named("event-broadcaster").Infof), - eventBroadcaster.StartRecordingToSink( - &v1.EventSinkImpl{Interface: client.Get(ctx).CoreV1().Events("")}), - } - recorder = eventBroadcaster.NewRecorder(scheme.Scheme, corev1.EventSource{Component: defaultControllerAgentName}) - go func() { - <-ctx.Done() - for _, w := range watches { - w.Stop() - } - }() - } - - rec := &reconcilerImpl{ - Client: injectionclient.Get(ctx), - Lister: containersourceInformer.Lister(), - Recorder: recorder, - reconciler: r, - } - impl := controller.NewImpl(rec, logger, defaultQueueName) - - // Pass impl to the options. Save any optional results. - for _, fn := range optionsFns { - opts := fn(impl) - if opts.ConfigStore != nil { - rec.configStore = opts.ConfigStore - } - } - - return impl -} - -func init() { - versionedscheme.AddToScheme(scheme.Scheme) -} diff --git a/pkg/client/injection/reconciler/sources/v1alpha1/containersource/reconciler.go b/pkg/client/injection/reconciler/sources/v1alpha1/containersource/reconciler.go deleted file mode 100644 index 017b4d64866..00000000000 --- a/pkg/client/injection/reconciler/sources/v1alpha1/containersource/reconciler.go +++ /dev/null @@ -1,339 +0,0 @@ -/* -Copyright 2020 The Knative Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by injection-gen. DO NOT EDIT. - -package containersource - -import ( - context "context" - "encoding/json" - "reflect" - - zap "go.uber.org/zap" - v1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/equality" - errors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - sets "k8s.io/apimachinery/pkg/util/sets" - cache "k8s.io/client-go/tools/cache" - record "k8s.io/client-go/tools/record" - v1alpha1 "knative.dev/eventing/pkg/apis/sources/v1alpha1" - versioned "knative.dev/eventing/pkg/client/clientset/versioned" - sourcesv1alpha1 "knative.dev/eventing/pkg/client/listers/sources/v1alpha1" - controller "knative.dev/pkg/controller" - logging "knative.dev/pkg/logging" - reconciler "knative.dev/pkg/reconciler" -) - -// Interface defines the strongly typed interfaces to be implemented by a -// controller reconciling v1alpha1.ContainerSource. -type Interface interface { - // ReconcileKind implements custom logic to reconcile v1alpha1.ContainerSource. Any changes - // to the objects .Status or .Finalizers will be propagated to the stored - // object. It is recommended that implementors do not call any update calls - // for the Kind inside of ReconcileKind, it is the responsibility of the calling - // controller to propagate those properties. The resource passed to ReconcileKind - // will always have an empty deletion timestamp. - ReconcileKind(ctx context.Context, o *v1alpha1.ContainerSource) reconciler.Event -} - -// Finalizer defines the strongly typed interfaces to be implemented by a -// controller finalizing v1alpha1.ContainerSource. -type Finalizer interface { - // FinalizeKind implements custom logic to finalize v1alpha1.ContainerSource. Any changes - // to the objects .Status or .Finalizers will be ignored. Returning a nil or - // Normal type reconciler.Event will allow the finalizer to be deleted on - // the resource. The resource passed to FinalizeKind will always have a set - // deletion timestamp. - FinalizeKind(ctx context.Context, o *v1alpha1.ContainerSource) reconciler.Event -} - -// reconcilerImpl implements controller.Reconciler for v1alpha1.ContainerSource resources. -type reconcilerImpl struct { - // Client is used to write back status updates. - Client versioned.Interface - - // Listers index properties about resources - Lister sourcesv1alpha1.ContainerSourceLister - - // Recorder is an event recorder for recording Event resources to the - // Kubernetes API. - Recorder record.EventRecorder - - // configStore allows for decorating a context with config maps. - // +optional - configStore reconciler.ConfigStore - - // reconciler is the implementation of the business logic of the resource. - reconciler Interface -} - -// Check that our Reconciler implements controller.Reconciler -var _ controller.Reconciler = (*reconcilerImpl)(nil) - -func NewReconciler(ctx context.Context, logger *zap.SugaredLogger, client versioned.Interface, lister sourcesv1alpha1.ContainerSourceLister, recorder record.EventRecorder, r Interface, options ...controller.Options) controller.Reconciler { - // Check the options function input. It should be 0 or 1. - if len(options) > 1 { - logger.Fatalf("up to one options struct is supported, found %d", len(options)) - } - - rec := &reconcilerImpl{ - Client: client, - Lister: lister, - Recorder: recorder, - reconciler: r, - } - - for _, opts := range options { - if opts.ConfigStore != nil { - rec.configStore = opts.ConfigStore - } - } - - return rec -} - -// Reconcile implements controller.Reconciler -func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { - logger := logging.FromContext(ctx) - - // If configStore is set, attach the frozen configuration to the context. - if r.configStore != nil { - ctx = r.configStore.ToContext(ctx) - } - - // Add the recorder to context. - ctx = controller.WithEventRecorder(ctx, r.Recorder) - - // Convert the namespace/name string into a distinct namespace and name - - namespace, name, err := cache.SplitMetaNamespaceKey(key) - - if err != nil { - logger.Errorf("invalid resource key: %s", key) - return nil - } - - // Get the resource with this namespace/name. - - getter := r.Lister.ContainerSources(namespace) - - original, err := getter.Get(name) - - if errors.IsNotFound(err) { - // The resource may no longer exist, in which case we stop processing. - logger.Errorf("resource %q no longer exists", key) - return nil - } else if err != nil { - return err - } - - // Don't modify the informers copy. - resource := original.DeepCopy() - - var reconcileEvent reconciler.Event - if resource.GetDeletionTimestamp().IsZero() { - // Append the target method to the logger. - logger = logger.With(zap.String("targetMethod", "ReconcileKind")) - - // Set and update the finalizer on resource if r.reconciler - // implements Finalizer. - if resource, err = r.setFinalizerIfFinalizer(ctx, resource); err != nil { - logger.Warnw("Failed to set finalizers", zap.Error(err)) - } - - // Reconcile this copy of the resource and then write back any status - // updates regardless of whether the reconciliation errored out. - reconcileEvent = r.reconciler.ReconcileKind(ctx, resource) - } else if fin, ok := r.reconciler.(Finalizer); ok { - // Append the target method to the logger. - logger = logger.With(zap.String("targetMethod", "FinalizeKind")) - - // For finalizing reconcilers, if this resource being marked for deletion - // and reconciled cleanly (nil or normal event), remove the finalizer. - reconcileEvent = fin.FinalizeKind(ctx, resource) - if resource, err = r.clearFinalizer(ctx, resource, reconcileEvent); err != nil { - logger.Warnw("Failed to clear finalizers", zap.Error(err)) - } - } - - // Synchronize the status. - if equality.Semantic.DeepEqual(original.Status, resource.Status) { - // If we didn't change anything then don't call updateStatus. - // This is important because the copy we loaded from the injectionInformer's - // cache may be stale and we don't want to overwrite a prior update - // to status with this stale state. - } else if err = r.updateStatus(original, resource); err != nil { - logger.Warnw("Failed to update resource status", zap.Error(err)) - r.Recorder.Eventf(resource, v1.EventTypeWarning, "UpdateFailed", - "Failed to update status for %q: %v", resource.Name, err) - return err - } - - // Report the reconciler event, if any. - if reconcileEvent != nil { - var event *reconciler.ReconcilerEvent - if reconciler.EventAs(reconcileEvent, &event) { - logger.Infow("returned an event", zap.Any("event", reconcileEvent)) - r.Recorder.Eventf(resource, event.EventType, event.Reason, event.Format, event.Args...) - return nil - } else { - logger.Errorw("returned an error", zap.Error(reconcileEvent)) - r.Recorder.Event(resource, v1.EventTypeWarning, "InternalError", reconcileEvent.Error()) - return reconcileEvent - } - } - return nil -} - -func (r *reconcilerImpl) updateStatus(existing *v1alpha1.ContainerSource, desired *v1alpha1.ContainerSource) error { - existing = existing.DeepCopy() - return reconciler.RetryUpdateConflicts(func(attempts int) (err error) { - // The first iteration tries to use the injectionInformer's state, subsequent attempts fetch the latest state via API. - if attempts > 0 { - - getter := r.Client.SourcesV1alpha1().ContainerSources(desired.Namespace) - - existing, err = getter.Get(desired.Name, metav1.GetOptions{}) - if err != nil { - return err - } - } - - // If there's nothing to update, just return. - if reflect.DeepEqual(existing.Status, desired.Status) { - return nil - } - - existing.Status = desired.Status - - updater := r.Client.SourcesV1alpha1().ContainerSources(existing.Namespace) - - _, err = updater.UpdateStatus(existing) - return err - }) -} - -// updateFinalizersFiltered will update the Finalizers of the resource. -// TODO: this method could be generic and sync all finalizers. For now it only -// updates defaultFinalizerName. -func (r *reconcilerImpl) updateFinalizersFiltered(ctx context.Context, resource *v1alpha1.ContainerSource) (*v1alpha1.ContainerSource, error) { - finalizerName := defaultFinalizerName - - getter := r.Lister.ContainerSources(resource.Namespace) - - actual, err := getter.Get(resource.Name) - if err != nil { - return resource, err - } - - // Don't modify the informers copy. - existing := actual.DeepCopy() - - var finalizers []string - - // If there's nothing to update, just return. - existingFinalizers := sets.NewString(existing.Finalizers...) - desiredFinalizers := sets.NewString(resource.Finalizers...) - - if desiredFinalizers.Has(finalizerName) { - if existingFinalizers.Has(finalizerName) { - // Nothing to do. - return resource, nil - } - // Add the finalizer. - finalizers = append(existing.Finalizers, finalizerName) - } else { - if !existingFinalizers.Has(finalizerName) { - // Nothing to do. - return resource, nil - } - // Remove the finalizer. - existingFinalizers.Delete(finalizerName) - finalizers = existingFinalizers.List() - } - - mergePatch := map[string]interface{}{ - "metadata": map[string]interface{}{ - "finalizers": finalizers, - "resourceVersion": existing.ResourceVersion, - }, - } - - patch, err := json.Marshal(mergePatch) - if err != nil { - return resource, err - } - - patcher := r.Client.SourcesV1alpha1().ContainerSources(resource.Namespace) - - resource, err = patcher.Patch(resource.Name, types.MergePatchType, patch) - if err != nil { - r.Recorder.Eventf(resource, v1.EventTypeWarning, "FinalizerUpdateFailed", - "Failed to update finalizers for %q: %v", resource.Name, err) - } else { - r.Recorder.Eventf(resource, v1.EventTypeNormal, "FinalizerUpdate", - "Updated %q finalizers", resource.GetName()) - } - return resource, err -} - -func (r *reconcilerImpl) setFinalizerIfFinalizer(ctx context.Context, resource *v1alpha1.ContainerSource) (*v1alpha1.ContainerSource, error) { - if _, ok := r.reconciler.(Finalizer); !ok { - return resource, nil - } - - finalizers := sets.NewString(resource.Finalizers...) - - // If this resource is not being deleted, mark the finalizer. - if resource.GetDeletionTimestamp().IsZero() { - finalizers.Insert(defaultFinalizerName) - } - - resource.Finalizers = finalizers.List() - - // Synchronize the finalizers filtered by defaultFinalizerName. - return r.updateFinalizersFiltered(ctx, resource) -} - -func (r *reconcilerImpl) clearFinalizer(ctx context.Context, resource *v1alpha1.ContainerSource, reconcileEvent reconciler.Event) (*v1alpha1.ContainerSource, error) { - if _, ok := r.reconciler.(Finalizer); !ok { - return resource, nil - } - if resource.GetDeletionTimestamp().IsZero() { - return resource, nil - } - - finalizers := sets.NewString(resource.Finalizers...) - - if reconcileEvent != nil { - var event *reconciler.ReconcilerEvent - if reconciler.EventAs(reconcileEvent, &event) { - if event.EventType == v1.EventTypeNormal { - finalizers.Delete(defaultFinalizerName) - } - } - } else { - finalizers.Delete(defaultFinalizerName) - } - - resource.Finalizers = finalizers.List() - - // Synchronize the finalizers filtered by defaultFinalizerName. - return r.updateFinalizersFiltered(ctx, resource) -} diff --git a/pkg/client/injection/reconciler/sources/v1alpha1/containersource/stub/controller.go b/pkg/client/injection/reconciler/sources/v1alpha1/containersource/stub/controller.go deleted file mode 100644 index 08a2140e82d..00000000000 --- a/pkg/client/injection/reconciler/sources/v1alpha1/containersource/stub/controller.go +++ /dev/null @@ -1,54 +0,0 @@ -/* -Copyright 2020 The Knative Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by injection-gen. DO NOT EDIT. - -package containersource - -import ( - context "context" - - containersource "knative.dev/eventing/pkg/client/injection/informers/sources/v1alpha1/containersource" - v1alpha1containersource "knative.dev/eventing/pkg/client/injection/reconciler/sources/v1alpha1/containersource" - configmap "knative.dev/pkg/configmap" - controller "knative.dev/pkg/controller" - logging "knative.dev/pkg/logging" -) - -// TODO: PLEASE COPY AND MODIFY THIS FILE AS A STARTING POINT - -// NewController creates a Reconciler for ContainerSource and returns the result of NewImpl. -func NewController( - ctx context.Context, - cmw configmap.Watcher, -) *controller.Impl { - logger := logging.FromContext(ctx) - - containersourceInformer := containersource.Get(ctx) - - // TODO: setup additional informers here. - - r := &Reconciler{} - impl := v1alpha1containersource.NewImpl(ctx, r) - - logger.Info("Setting up event handlers.") - - containersourceInformer.Informer().AddEventHandler(controller.HandleAll(impl.Enqueue)) - - // TODO: add additional informer event handlers here. - - return impl -} diff --git a/pkg/client/injection/reconciler/sources/v1alpha1/containersource/stub/reconciler.go b/pkg/client/injection/reconciler/sources/v1alpha1/containersource/stub/reconciler.go deleted file mode 100644 index c0d28912a3c..00000000000 --- a/pkg/client/injection/reconciler/sources/v1alpha1/containersource/stub/reconciler.go +++ /dev/null @@ -1,66 +0,0 @@ -/* -Copyright 2020 The Knative Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by injection-gen. DO NOT EDIT. - -package containersource - -import ( - context "context" - - v1 "k8s.io/api/core/v1" - v1alpha1 "knative.dev/eventing/pkg/apis/sources/v1alpha1" - containersource "knative.dev/eventing/pkg/client/injection/reconciler/sources/v1alpha1/containersource" - reconciler "knative.dev/pkg/reconciler" -) - -// TODO: PLEASE COPY AND MODIFY THIS FILE AS A STARTING POINT - -// newReconciledNormal makes a new reconciler event with event type Normal, and -// reason ContainerSourceReconciled. -func newReconciledNormal(namespace, name string) reconciler.Event { - return reconciler.NewEvent(v1.EventTypeNormal, "ContainerSourceReconciled", "ContainerSource reconciled: \"%s/%s\"", namespace, name) -} - -// Reconciler implements controller.Reconciler for ContainerSource resources. -type Reconciler struct { - // TODO: add additional requirements here. -} - -// Check that our Reconciler implements Interface -var _ containersource.Interface = (*Reconciler)(nil) - -// Optionally check that our Reconciler implements Finalizer -//var _ containersource.Finalizer = (*Reconciler)(nil) - -// ReconcileKind implements Interface.ReconcileKind. -func (r *Reconciler) ReconcileKind(ctx context.Context, o *v1alpha1.ContainerSource) reconciler.Event { - // TODO: use this if the resource implements InitializeConditions. - // o.Status.InitializeConditions() - - // TODO: add custom reconciliation logic here. - - // TODO: use this if the object has .status.ObservedGeneration. - // o.Status.ObservedGeneration = o.Generation - return newReconciledNormal(o.Namespace, o.Name) -} - -// Optionally, use FinalizeKind to add finalizers. FinalizeKind will be called -// when the resource is deleted. -//func (r *Reconciler) FinalizeKind(ctx context.Context, o *v1alpha1.ContainerSource) reconciler.Event { -// // TODO: add custom finalization logic here. -// return nil -//} diff --git a/pkg/client/listers/sources/v1alpha1/containersource.go b/pkg/client/listers/sources/v1alpha1/containersource.go deleted file mode 100644 index 8ac0cddfce8..00000000000 --- a/pkg/client/listers/sources/v1alpha1/containersource.go +++ /dev/null @@ -1,94 +0,0 @@ -/* -Copyright 2020 The Knative Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by lister-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/client-go/tools/cache" - v1alpha1 "knative.dev/eventing/pkg/apis/sources/v1alpha1" -) - -// 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/reconciler/containersource/containersource.go b/pkg/reconciler/containersource/containersource.go index 5b3122122de..ab83c832344 100644 --- a/pkg/reconciler/containersource/containersource.go +++ b/pkg/reconciler/containersource/containersource.go @@ -19,8 +19,6 @@ package containersource import ( "context" "fmt" - "knative.dev/eventing/pkg/apis/sources/v1alpha1" - "go.uber.org/zap" appsv1 "k8s.io/api/apps/v1" @@ -32,8 +30,8 @@ import ( appsv1listers "k8s.io/client-go/listers/apps/v1" "knative.dev/eventing/pkg/apis/sources/v1alpha2" clientset "knative.dev/eventing/pkg/client/clientset/versioned" - "knative.dev/eventing/pkg/client/injection/reconciler/sources/v1alpha1/containersource" - listers "knative.dev/eventing/pkg/client/listers/sources/v1alpha1" + "knative.dev/eventing/pkg/client/injection/reconciler/sources/v1alpha2/containersource" + listers "knative.dev/eventing/pkg/client/listers/sources/v1alpha2" "knative.dev/eventing/pkg/logging" "knative.dev/eventing/pkg/reconciler/containersource/resources" "knative.dev/pkg/controller" @@ -119,13 +117,13 @@ func (r *Reconciler) reconcileReceiveAdapter(ctx context.Context, source *v1alph return ra, nil } -func (r *Reconciler) reconcileSinkBinding(ctx context.Context, source *v1alpha1.ContainerSource) (*v1alpha1.SinkBinding, error) { +func (r *Reconciler) reconcileSinkBinding(ctx context.Context, source *v1alpha2.ContainerSource) (*v1alpha2.SinkBinding, error) { expected := resources.MakeSinkBinding(source) sb, err := r.sinkBindingLister.SinkBindings(source.Namespace).Get(expected.Name) if apierrors.IsNotFound(err) { - sb, err = r.eventingClientSet.SourcesV1alpha1().SinkBindings(source.Namespace).Create(expected) + sb, err = r.eventingClientSet.SourcesV1alpha2().SinkBindings(source.Namespace).Create(expected) if err != nil { return nil, fmt.Errorf("creating new SinkBinding: %v", err) } @@ -136,7 +134,7 @@ func (r *Reconciler) reconcileSinkBinding(ctx context.Context, source *v1alpha1. return nil, fmt.Errorf("SinkBinding %q is not owned by ContainerSource %q", sb.Name, source.Name) } else if r.sinkBindingSpecChanged(&sb.Spec, &expected.Spec) { sb.Spec = expected.Spec - sb, err = r.eventingClientSet.SourcesV1alpha1().SinkBindings(source.Namespace).Update(sb) + sb, err = r.eventingClientSet.SourcesV1alpha2().SinkBindings(source.Namespace).Update(sb) if err != nil { return nil, fmt.Errorf("updating SinkBinding: %v", err) } @@ -153,6 +151,6 @@ func (r *Reconciler) podSpecChanged(have *corev1.PodSpec, want *corev1.PodSpec) return !equality.Semantic.DeepDerivative(want, have) } -func (r *Reconciler) sinkBindingSpecChanged(have *v1alpha1.SinkBindingSpec, want *v1alpha1.SinkBindingSpec) bool { +func (r *Reconciler) sinkBindingSpecChanged(have *v1alpha2.SinkBindingSpec, want *v1alpha2.SinkBindingSpec) bool { return !equality.Semantic.DeepDerivative(want, have) } diff --git a/pkg/reconciler/containersource/containersource_test.go b/pkg/reconciler/containersource/containersource_test.go index 26ea2e176ba..c44fc205b95 100644 --- a/pkg/reconciler/containersource/containersource_test.go +++ b/pkg/reconciler/containersource/containersource_test.go @@ -35,7 +35,7 @@ import ( fakekubeclient "knative.dev/pkg/client/injection/kube/client/fake" "knative.dev/pkg/logging" - "knative.dev/eventing/pkg/client/injection/reconciler/sources/v1alpha1/containersource" + "knative.dev/eventing/pkg/client/injection/reconciler/sources/v1alpha2/containersource" "knative.dev/eventing/pkg/reconciler/containersource/resources" duckv1 "knative.dev/pkg/apis/duck/v1" duckv1alpha1 "knative.dev/pkg/apis/duck/v1alpha1" @@ -44,7 +44,7 @@ import ( "knative.dev/pkg/configmap" "knative.dev/pkg/controller" - sourcesv1alpha1 "knative.dev/eventing/pkg/apis/sources/v1alpha1" + sourcesv1alpha2 "knative.dev/eventing/pkg/apis/sources/v1alpha2" "knative.dev/eventing/pkg/utils" logtesting "knative.dev/pkg/logging/testing" @@ -260,7 +260,7 @@ func TestAllCases(t *testing.T) { eventingClientSet: fakeeventingclient.Get(ctx), containerSourceLister: listers.GetContainerSourceLister(), deploymentLister: listers.GetDeploymentLister(), - sinkBindingLister: listers.GetSinkBindingLister(), + sinkBindingLister: listers.GetSinkBindingV1alpha2Lister(), } return containersource.NewReconciler(ctx, logging.FromContext(ctx), fakeeventingclient.Get(ctx), listers.GetContainerSourceLister(), controller.GetEventRecorder(ctx), r) }, @@ -269,8 +269,8 @@ func TestAllCases(t *testing.T) { )) } -func makeSinkBinding(source *sourcesv1alpha1.ContainerSource, ready *corev1.ConditionStatus) *sourcesv1alpha1.SinkBinding { - sb := &sourcesv1alpha1.SinkBinding{ +func makeSinkBinding(source *sourcesv1alpha2.ContainerSource, ready *corev1.ConditionStatus) *sourcesv1alpha2.SinkBinding { + sb := &sourcesv1alpha2.SinkBinding{ ObjectMeta: metav1.ObjectMeta{ OwnerReferences: []metav1.OwnerReference{ *kmeta.NewControllerRef(source), @@ -278,7 +278,7 @@ func makeSinkBinding(source *sourcesv1alpha1.ContainerSource, ready *corev1.Cond Name: sinkBindingName, Namespace: source.Namespace, }, - Spec: sourcesv1alpha1.SinkBindingSpec{ + Spec: sourcesv1alpha2.SinkBindingSpec{ SourceSpec: source.Spec.SourceSpec, BindingSpec: duckv1alpha1.BindingSpec{ Subject: tracker.Reference{ @@ -296,7 +296,7 @@ func makeSinkBinding(source *sourcesv1alpha1.ContainerSource, ready *corev1.Cond return sb } -func makeDeployment(source *sourcesv1alpha1.ContainerSource, available *corev1.ConditionStatus) *appsv1.Deployment { +func makeDeployment(source *sourcesv1alpha2.ContainerSource, available *corev1.ConditionStatus) *appsv1.Deployment { template := source.Spec.Template if template.Labels == nil { @@ -342,7 +342,7 @@ func makeDeployment(source *sourcesv1alpha1.ContainerSource, available *corev1.C func getOwnerReferences() []metav1.OwnerReference { return []metav1.OwnerReference{{ - APIVersion: sourcesv1alpha1.SchemeGroupVersion.String(), + APIVersion: sourcesv1alpha2.SchemeGroupVersion.String(), Kind: "ContainerSource", Name: sourceName, Controller: &trueVal, @@ -351,8 +351,8 @@ func getOwnerReferences() []metav1.OwnerReference { }} } -func makeContainerSourceSpec(sink duckv1.Destination) sourcesv1alpha1.ContainerSourceSpec { - return sourcesv1alpha1.ContainerSourceSpec{ +func makeContainerSourceSpec(sink duckv1.Destination) sourcesv1alpha2.ContainerSourceSpec { + return sourcesv1alpha2.ContainerSourceSpec{ Template: corev1.PodTemplateSpec{ Spec: corev1.PodSpec{ Containers: []corev1.Container{ @@ -370,8 +370,8 @@ func makeContainerSourceSpec(sink duckv1.Destination) sourcesv1alpha1.ContainerS } } -func makeSinkBindingStatus(ready *corev1.ConditionStatus) *sourcesv1alpha1.SinkBindingStatus { - return &sourcesv1alpha1.SinkBindingStatus{ +func makeSinkBindingStatus(ready *corev1.ConditionStatus) *sourcesv1alpha2.SinkBindingStatus { + return &sourcesv1alpha2.SinkBindingStatus{ SourceStatus: duckv1.SourceStatus{ Status: duckv1.Status{ Conditions: []apis.Condition{{ diff --git a/pkg/reconciler/containersource/controller.go b/pkg/reconciler/containersource/controller.go index 1526465aa93..255b8fd4aa1 100644 --- a/pkg/reconciler/containersource/controller.go +++ b/pkg/reconciler/containersource/controller.go @@ -20,11 +20,11 @@ import ( "context" "k8s.io/client-go/tools/cache" - "knative.dev/eventing/pkg/apis/sources/v1alpha1" + "knative.dev/eventing/pkg/apis/sources/v1alpha2" eventingclient "knative.dev/eventing/pkg/client/injection/client" - containersourceinformer "knative.dev/eventing/pkg/client/injection/informers/sources/v1alpha1/containersource" - sinkbindinginformer "knative.dev/eventing/pkg/client/injection/informers/sources/v1alpha1/sinkbinding" - v1alpha1containersource "knative.dev/eventing/pkg/client/injection/reconciler/sources/v1alpha1/containersource" + containersourceinformer "knative.dev/eventing/pkg/client/injection/informers/sources/v1alpha2/containersource" + sinkbindinginformer "knative.dev/eventing/pkg/client/injection/informers/sources/v1alpha2/sinkbinding" + v1alpha2containersource "knative.dev/eventing/pkg/client/injection/reconciler/sources/v1alpha2/containersource" kubeclient "knative.dev/pkg/client/injection/kube/client" deploymentinformer "knative.dev/pkg/client/injection/kube/informers/apps/v1/deployment" "knative.dev/pkg/configmap" @@ -51,18 +51,18 @@ func NewController( deploymentLister: deploymentInformer.Lister(), sinkBindingLister: sinkbindingInformer.Lister(), } - impl := v1alpha1containersource.NewImpl(ctx, r) + impl := v1alpha2containersource.NewImpl(ctx, r) logging.FromContext(ctx).Info("Setting up event handlers.") containersourceInformer.Informer().AddEventHandler(controller.HandleAll(impl.Enqueue)) deploymentInformer.Informer().AddEventHandler(cache.FilteringResourceEventHandler{ - FilterFunc: controller.FilterGroupVersionKind(v1alpha1.SchemeGroupVersion.WithKind("ContainerSource")), + FilterFunc: controller.FilterGroupVersionKind(v1alpha2.SchemeGroupVersion.WithKind("ContainerSource")), Handler: controller.HandleAll(impl.EnqueueControllerOf), }) sinkbindingInformer.Informer().AddEventHandler(cache.FilteringResourceEventHandler{ - FilterFunc: controller.FilterGroupKind(v1alpha1.Kind("ContainerSource")), + FilterFunc: controller.FilterGroupKind(v1alpha2.Kind("ContainerSource")), Handler: controller.HandleAll(impl.EnqueueControllerOf), }) diff --git a/pkg/reconciler/containersource/controller_test.go b/pkg/reconciler/containersource/controller_test.go index e990c35d071..61369386833 100644 --- a/pkg/reconciler/containersource/controller_test.go +++ b/pkg/reconciler/containersource/controller_test.go @@ -23,8 +23,8 @@ import ( . "knative.dev/pkg/reconciler/testing" // Fake injection informers - _ "knative.dev/eventing/pkg/client/injection/informers/sources/v1alpha1/containersource/fake" - _ "knative.dev/eventing/pkg/client/injection/informers/sources/v1alpha1/sinkbinding/fake" + _ "knative.dev/eventing/pkg/client/injection/informers/sources/v1alpha2/containersource/fake" + _ "knative.dev/eventing/pkg/client/injection/informers/sources/v1alpha2/sinkbinding/fake" _ "knative.dev/pkg/client/injection/kube/informers/apps/v1/deployment/fake" _ "knative.dev/pkg/injection/clients/dynamicclient/fake" ) diff --git a/pkg/reconciler/containersource/resources/sinkbinding.go b/pkg/reconciler/containersource/resources/sinkbinding.go index 64f0a0e0aaf..01beadae9cf 100644 --- a/pkg/reconciler/containersource/resources/sinkbinding.go +++ b/pkg/reconciler/containersource/resources/sinkbinding.go @@ -19,7 +19,7 @@ package resources import ( appsv1 "k8s.io/api/apps/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "knative.dev/eventing/pkg/apis/sources/v1alpha1" + "knative.dev/eventing/pkg/apis/sources/v1alpha2" duckv1alpha1 "knative.dev/pkg/apis/duck/v1alpha1" "knative.dev/pkg/kmeta" "knative.dev/pkg/tracker" @@ -27,10 +27,10 @@ import ( var subjectGVK = appsv1.SchemeGroupVersion.WithKind("Deployment") -func MakeSinkBinding(source *v1alpha1.ContainerSource) *v1alpha1.SinkBinding { +func MakeSinkBinding(source *v1alpha2.ContainerSource) *v1alpha2.SinkBinding { subjectAPIVersion, subjectKind := subjectGVK.ToAPIVersionAndKind() - sb := &v1alpha1.SinkBinding{ + sb := &v1alpha2.SinkBinding{ ObjectMeta: metav1.ObjectMeta{ OwnerReferences: []metav1.OwnerReference{ *kmeta.NewControllerRef(source), @@ -38,7 +38,7 @@ func MakeSinkBinding(source *v1alpha1.ContainerSource) *v1alpha1.SinkBinding { Name: SinkBindingName(source), Namespace: source.Namespace, }, - Spec: v1alpha1.SinkBindingSpec{ + Spec: v1alpha2.SinkBindingSpec{ SourceSpec: source.Spec.SourceSpec, BindingSpec: duckv1alpha1.BindingSpec{ Subject: tracker.Reference{ diff --git a/pkg/reconciler/testing/containersource.go b/pkg/reconciler/testing/containersource.go index e571c915f49..ebbbd7fce66 100644 --- a/pkg/reconciler/testing/containersource.go +++ b/pkg/reconciler/testing/containersource.go @@ -23,15 +23,15 @@ import ( appsv1 "k8s.io/api/apps/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" - sourcesv1alpha1 "knative.dev/eventing/pkg/apis/sources/v1alpha1" + sourcesv1alpha2 "knative.dev/eventing/pkg/apis/sources/v1alpha2" ) // ContainerSourceOption enables further configuration of a ContainerSource. -type ContainerSourceOption func(*sourcesv1alpha1.ContainerSource) +type ContainerSourceOption func(*sourcesv1alpha2.ContainerSource) // NewContainerSource creates a ContainerSource with ContainerSourceOptions -func NewContainerSource(name, namespace string, o ...ContainerSourceOption) *sourcesv1alpha1.ContainerSource { - c := &sourcesv1alpha1.ContainerSource{ +func NewContainerSource(name, namespace string, o ...ContainerSourceOption) *sourcesv1alpha2.ContainerSource { + c := &sourcesv1alpha2.ContainerSource{ ObjectMeta: metav1.ObjectMeta{ Name: name, Namespace: namespace, @@ -45,59 +45,59 @@ func NewContainerSource(name, namespace string, o ...ContainerSourceOption) *sou } func WithContainerSourceUID(uid types.UID) ContainerSourceOption { - return func(s *sourcesv1alpha1.ContainerSource) { + return func(s *sourcesv1alpha2.ContainerSource) { s.UID = uid } } // WithInitContainerSourceConditions initializes the ContainerSource's conditions. -func WithInitContainerSourceConditions(s *sourcesv1alpha1.ContainerSource) { +func WithInitContainerSourceConditions(s *sourcesv1alpha2.ContainerSource) { s.Status.InitializeConditions() } func WithContainerSourcePropagateReceiveAdapterStatus(d *appsv1.Deployment) ContainerSourceOption { - return func(s *sourcesv1alpha1.ContainerSource) { + return func(s *sourcesv1alpha2.ContainerSource) { s.Status.PropagateReceiveAdapterStatus(d) } } -func WithContainerSourcePropagateSinkbindingStatus(status *sourcesv1alpha1.SinkBindingStatus) ContainerSourceOption { - return func(s *sourcesv1alpha1.ContainerSource) { +func WithContainerSourcePropagateSinkbindingStatus(status *sourcesv1alpha2.SinkBindingStatus) ContainerSourceOption { + return func(s *sourcesv1alpha2.ContainerSource) { s.Status.PropagateSinkBindingStatus(status) } } -func WithContainerSourceDeleted(c *sourcesv1alpha1.ContainerSource) { +func WithContainerSourceDeleted(c *sourcesv1alpha2.ContainerSource) { t := metav1.NewTime(time.Unix(1e9, 0)) c.ObjectMeta.SetDeletionTimestamp(&t) } -func WithContainerSourceSpec(spec sourcesv1alpha1.ContainerSourceSpec) ContainerSourceOption { - return func(c *sourcesv1alpha1.ContainerSource) { +func WithContainerSourceSpec(spec sourcesv1alpha2.ContainerSourceSpec) ContainerSourceOption { + return func(c *sourcesv1alpha2.ContainerSource) { c.Spec = spec } } func WithContainerSourceLabels(labels map[string]string) ContainerSourceOption { - return func(c *sourcesv1alpha1.ContainerSource) { + return func(c *sourcesv1alpha2.ContainerSource) { c.Labels = labels } } func WithContainerSourceAnnotations(annotations map[string]string) ContainerSourceOption { - return func(c *sourcesv1alpha1.ContainerSource) { + return func(c *sourcesv1alpha2.ContainerSource) { c.Annotations = annotations } } func WithContainerSourceStatusObservedGeneration(generation int64) ContainerSourceOption { - return func(c *sourcesv1alpha1.ContainerSource) { + return func(c *sourcesv1alpha2.ContainerSource) { c.Status.ObservedGeneration = generation } } func WithContainerSourceObjectMetaGeneration(generation int64) ContainerSourceOption { - return func(c *sourcesv1alpha1.ContainerSource) { + return func(c *sourcesv1alpha2.ContainerSource) { c.ObjectMeta.Generation = generation } } diff --git a/pkg/reconciler/testing/listers.go b/pkg/reconciler/testing/listers.go index b50771b6b33..f56ddda4b99 100644 --- a/pkg/reconciler/testing/listers.go +++ b/pkg/reconciler/testing/listers.go @@ -164,10 +164,6 @@ func (l *Listers) GetPingSourceLister() sourcelisters.PingSourceLister { return sourcelisters.NewPingSourceLister(l.indexerFor(&sourcesv1alpha1.PingSource{})) } -func (l *Listers) GetContainerSourceLister() sourcelisters.ContainerSourceLister { - return sourcelisters.NewContainerSourceLister(l.indexerFor(&sourcesv1alpha1.ContainerSource{})) -} - func (l *Listers) GetSinkBindingLister() sourcelisters.SinkBindingLister { return sourcelisters.NewSinkBindingLister(l.indexerFor(&sourcesv1alpha1.SinkBinding{})) } @@ -176,6 +172,14 @@ func (l *Listers) GetPingSourceV1alpha2Lister() sourcev1alpha2listers.PingSource return sourcev1alpha2listers.NewPingSourceLister(l.indexerFor(&sourcesv1alpha2.PingSource{})) } +func (l *Listers) GetContainerSourceLister() sourcev1alpha2listers.ContainerSourceLister { + return sourcev1alpha2listers.NewContainerSourceLister(l.indexerFor(&sourcesv1alpha2.ContainerSource{})) +} + +func (l *Listers) GetSinkBindingV1alpha2Lister() sourcev1alpha2listers.SinkBindingLister { + return sourcev1alpha2listers.NewSinkBindingLister(l.indexerFor(&sourcesv1alpha2.SinkBinding{})) +} + func (l *Listers) GetDeploymentLister() appsv1listers.DeploymentLister { return appsv1listers.NewDeploymentLister(l.indexerFor(&appsv1.Deployment{})) } From 29a0eaff9ff0b9163a43ab3193ae376c0ad5779e Mon Sep 17 00:00:00 2001 From: nachocano Date: Thu, 26 Mar 2020 14:42:35 -0700 Subject: [PATCH 11/16] update codegen --- .../sources/v1alpha1/zz_generated.deepcopy.go | 96 ------------------- .../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/interface.go | 7 -- .../sources/v1alpha1/expansion_generated.go | 8 -- 7 files changed, 124 deletions(-) diff --git a/pkg/apis/sources/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/sources/v1alpha1/zz_generated.deepcopy.go index 3eaf09efa9c..40338335045 100644 --- a/pkg/apis/sources/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/sources/v1alpha1/zz_generated.deepcopy.go @@ -167,102 +167,6 @@ func (in *ApiServerSourceStatus) DeepCopy() *ApiServerSourceStatus { 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 - in.ListMeta.DeepCopyInto(&out.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 - in.SourceSpec.DeepCopyInto(&out.SourceSpec) - in.Template.DeepCopyInto(&out.Template) - 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.SourceStatus.DeepCopyInto(&out.SourceStatus) - 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 *PingLimitsSpec) DeepCopyInto(out *PingLimitsSpec) { *out = *in 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 d1be82fdf97..59cd493e70b 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 @@ -32,10 +32,6 @@ func (c *FakeSourcesV1alpha1) ApiServerSources(namespace string) v1alpha1.ApiSer return &FakeApiServerSources{c, namespace} } -func (c *FakeSourcesV1alpha1) ContainerSources(namespace string) v1alpha1.ContainerSourceInterface { - return &FakeContainerSources{c, namespace} -} - func (c *FakeSourcesV1alpha1) PingSources(namespace string) v1alpha1.PingSourceInterface { return &FakePingSources{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 f8047e557db..aa618931ea9 100644 --- a/pkg/client/clientset/versioned/typed/sources/v1alpha1/generated_expansion.go +++ b/pkg/client/clientset/versioned/typed/sources/v1alpha1/generated_expansion.go @@ -20,8 +20,6 @@ package v1alpha1 type ApiServerSourceExpansion interface{} -type ContainerSourceExpansion interface{} - type PingSourceExpansion interface{} type SinkBindingExpansion 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 f505eb3e6ae..08031fe8049 100644 --- a/pkg/client/clientset/versioned/typed/sources/v1alpha1/sources_client.go +++ b/pkg/client/clientset/versioned/typed/sources/v1alpha1/sources_client.go @@ -27,7 +27,6 @@ import ( type SourcesV1alpha1Interface interface { RESTClient() rest.Interface ApiServerSourcesGetter - ContainerSourcesGetter PingSourcesGetter SinkBindingsGetter } @@ -41,10 +40,6 @@ func (c *SourcesV1alpha1Client) ApiServerSources(namespace string) ApiServerSour return newApiServerSources(c, namespace) } -func (c *SourcesV1alpha1Client) ContainerSources(namespace string) ContainerSourceInterface { - return newContainerSources(c, namespace) -} - func (c *SourcesV1alpha1Client) PingSources(namespace string) PingSourceInterface { return newPingSources(c, namespace) } diff --git a/pkg/client/informers/externalversions/generic.go b/pkg/client/informers/externalversions/generic.go index 60abc746c72..5732560b6c0 100644 --- a/pkg/client/informers/externalversions/generic.go +++ b/pkg/client/informers/externalversions/generic.go @@ -111,8 +111,6 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource // Group=sources.knative.dev, Version=v1alpha1 case sourcesv1alpha1.SchemeGroupVersion.WithResource("apiserversources"): return &genericInformer{resource: resource.GroupResource(), informer: f.Sources().V1alpha1().ApiServerSources().Informer()}, nil - case sourcesv1alpha1.SchemeGroupVersion.WithResource("containersources"): - return &genericInformer{resource: resource.GroupResource(), informer: f.Sources().V1alpha1().ContainerSources().Informer()}, nil case sourcesv1alpha1.SchemeGroupVersion.WithResource("pingsources"): return &genericInformer{resource: resource.GroupResource(), informer: f.Sources().V1alpha1().PingSources().Informer()}, nil case sourcesv1alpha1.SchemeGroupVersion.WithResource("sinkbindings"): diff --git a/pkg/client/informers/externalversions/sources/v1alpha1/interface.go b/pkg/client/informers/externalversions/sources/v1alpha1/interface.go index f8d4a5d4e2a..9ddc57ca546 100644 --- a/pkg/client/informers/externalversions/sources/v1alpha1/interface.go +++ b/pkg/client/informers/externalversions/sources/v1alpha1/interface.go @@ -26,8 +26,6 @@ import ( type Interface interface { // ApiServerSources returns a ApiServerSourceInformer. ApiServerSources() ApiServerSourceInformer - // ContainerSources returns a ContainerSourceInformer. - ContainerSources() ContainerSourceInformer // PingSources returns a PingSourceInformer. PingSources() PingSourceInformer // SinkBindings returns a SinkBindingInformer. @@ -50,11 +48,6 @@ func (v *version) ApiServerSources() ApiServerSourceInformer { return &apiServerSourceInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} } -// ContainerSources returns a ContainerSourceInformer. -func (v *version) ContainerSources() ContainerSourceInformer { - return &containerSourceInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} -} - // PingSources returns a PingSourceInformer. func (v *version) PingSources() PingSourceInformer { return &pingSourceInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} diff --git a/pkg/client/listers/sources/v1alpha1/expansion_generated.go b/pkg/client/listers/sources/v1alpha1/expansion_generated.go index 38f878705a5..f30287719ed 100644 --- a/pkg/client/listers/sources/v1alpha1/expansion_generated.go +++ b/pkg/client/listers/sources/v1alpha1/expansion_generated.go @@ -26,14 +26,6 @@ type ApiServerSourceListerExpansion interface{} // ApiServerSourceNamespaceLister. type ApiServerSourceNamespaceListerExpansion interface{} -// ContainerSourceListerExpansion allows custom methods to be added to -// ContainerSourceLister. -type ContainerSourceListerExpansion interface{} - -// ContainerSourceNamespaceListerExpansion allows custom methods to be added to -// ContainerSourceNamespaceLister. -type ContainerSourceNamespaceListerExpansion interface{} - // PingSourceListerExpansion allows custom methods to be added to // PingSourceLister. type PingSourceListerExpansion interface{} From d5f79952a17756aa3d3f3681118f122e6e17e185 Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Thu, 26 Mar 2020 15:08:23 -0700 Subject: [PATCH 12/16] one more try --- config/core/resources/containersource.yaml | 3 +++ .../containersource/containersource.go | 1 + .../containersource/resources/deployment.go | 2 +- .../resources/deployment_test.go | 20 +++++++++---------- .../containersource/resources/names.go | 6 +++--- .../resources/sinkbinding_test.go | 10 +++++----- 6 files changed, 23 insertions(+), 19 deletions(-) diff --git a/config/core/resources/containersource.yaml b/config/core/resources/containersource.yaml index 8dd3709f9e7..683c3f20121 100644 --- a/config/core/resources/containersource.yaml +++ b/config/core/resources/containersource.yaml @@ -57,6 +57,9 @@ spec: type: date JSONPath: .metadata.creationTimestamp versions: + - name: v1alpha1 + served: false + storage: false - name: v1alpha2 served: true storage: true diff --git a/pkg/reconciler/containersource/containersource.go b/pkg/reconciler/containersource/containersource.go index ab83c832344..e308e5d081f 100644 --- a/pkg/reconciler/containersource/containersource.go +++ b/pkg/reconciler/containersource/containersource.go @@ -148,6 +148,7 @@ func (r *Reconciler) reconcileSinkBinding(ctx context.Context, source *v1alpha2. } func (r *Reconciler) podSpecChanged(have *corev1.PodSpec, want *corev1.PodSpec) bool { + // TODO this won't work, SinkBinding messes with this. n3wscott working on a fix. return !equality.Semantic.DeepDerivative(want, have) } diff --git a/pkg/reconciler/containersource/resources/deployment.go b/pkg/reconciler/containersource/resources/deployment.go index e87de9eaa32..1b40d474289 100644 --- a/pkg/reconciler/containersource/resources/deployment.go +++ b/pkg/reconciler/containersource/resources/deployment.go @@ -19,7 +19,7 @@ package resources import ( appsv1 "k8s.io/api/apps/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - + "knative.dev/eventing/pkg/apis/sources/v1alpha2" "knative.dev/pkg/kmeta" ) diff --git a/pkg/reconciler/containersource/resources/deployment_test.go b/pkg/reconciler/containersource/resources/deployment_test.go index c435ef5de00..6040e88b73a 100644 --- a/pkg/reconciler/containersource/resources/deployment_test.go +++ b/pkg/reconciler/containersource/resources/deployment_test.go @@ -20,13 +20,13 @@ import ( "fmt" "testing" - "knative.dev/eventing/pkg/apis/sources/v1alpha1" - "knative.dev/pkg/apis" - "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" + "knative.dev/eventing/pkg/apis/sources/v1alpha2" + "knative.dev/pkg/apis" duckv1 "knative.dev/pkg/apis/duck/v1" ) @@ -39,14 +39,14 @@ func TestMakeDeployment(t *testing.T) { yes := true tests := []struct { name string - source *v1alpha1.ContainerSource + source *v1alpha2.ContainerSource want *appsv1.Deployment }{ { name: "valid container source with one container", - source: &v1alpha1.ContainerSource{ + source: &v1alpha2.ContainerSource{ ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: "test-namespace", UID: uid}, - Spec: v1alpha1.ContainerSourceSpec{ + Spec: v1alpha2.ContainerSourceSpec{ Template: corev1.PodTemplateSpec{ Spec: corev1.PodSpec{ ServiceAccountName: "test-service-account", @@ -90,7 +90,7 @@ func TestMakeDeployment(t *testing.T) { Name: fmt.Sprintf("%s-deployment", name), Namespace: "test-namespace", OwnerReferences: []metav1.OwnerReference{{ - APIVersion: "sources.knative.dev/v1alpha1", + APIVersion: "sources.knative.dev/v1alpha2", Kind: "ContainerSource", Name: name, UID: uid, @@ -149,9 +149,9 @@ func TestMakeDeployment(t *testing.T) { { name: "valid container source with two containers", - source: &v1alpha1.ContainerSource{ + source: &v1alpha2.ContainerSource{ ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: "test-namespace", UID: uid}, - Spec: v1alpha1.ContainerSourceSpec{ + Spec: v1alpha2.ContainerSourceSpec{ Template: corev1.PodTemplateSpec{ Spec: corev1.PodSpec{ ServiceAccountName: "test-service-account", @@ -212,7 +212,7 @@ func TestMakeDeployment(t *testing.T) { Name: fmt.Sprintf("%s-deployment", name), Namespace: "test-namespace", OwnerReferences: []metav1.OwnerReference{{ - APIVersion: "sources.knative.dev/v1alpha1", + APIVersion: "sources.knative.dev/v1alpha2", Kind: "ContainerSource", Name: name, UID: uid, diff --git a/pkg/reconciler/containersource/resources/names.go b/pkg/reconciler/containersource/resources/names.go index 773a8fe94f8..894fac12785 100644 --- a/pkg/reconciler/containersource/resources/names.go +++ b/pkg/reconciler/containersource/resources/names.go @@ -17,14 +17,14 @@ limitations under the License. package resources import ( - "knative.dev/eventing/pkg/apis/sources/v1alpha1" + "knative.dev/eventing/pkg/apis/sources/v1alpha2" "knative.dev/pkg/kmeta" ) -func DeploymentName(source *v1alpha1.ContainerSource) string { +func DeploymentName(source *v1alpha2.ContainerSource) string { return kmeta.ChildName(source.Name, "-deployment") } -func SinkBindingName(source *v1alpha1.ContainerSource) string { +func SinkBindingName(source *v1alpha2.ContainerSource) string { return kmeta.ChildName(source.Name, "-sinkbinding") } diff --git a/pkg/reconciler/containersource/resources/sinkbinding_test.go b/pkg/reconciler/containersource/resources/sinkbinding_test.go index 992813bc67f..fa57a1d2bf9 100644 --- a/pkg/reconciler/containersource/resources/sinkbinding_test.go +++ b/pkg/reconciler/containersource/resources/sinkbinding_test.go @@ -20,7 +20,7 @@ import ( "fmt" "testing" - "knative.dev/eventing/pkg/apis/sources/v1alpha1" + "knative.dev/eventing/pkg/apis/sources/v1alpha2" "knative.dev/pkg/apis" duckv1alpha1 "knative.dev/pkg/apis/duck/v1alpha1" "knative.dev/pkg/kmeta" @@ -38,9 +38,9 @@ const ( ) func TestMakeSinkBinding(t *testing.T) { - source := &v1alpha1.ContainerSource{ + source := &v1alpha2.ContainerSource{ ObjectMeta: metav1.ObjectMeta{Name: containerSourceName, Namespace: "test-namespace", UID: containerSourceUID}, - Spec: v1alpha1.ContainerSourceSpec{ + Spec: v1alpha2.ContainerSourceSpec{ Template: corev1.PodTemplateSpec{ Spec: corev1.PodSpec{ ServiceAccountName: "test-service-account", @@ -76,7 +76,7 @@ func TestMakeSinkBinding(t *testing.T) { }, } - want := &v1alpha1.SinkBinding{ + want := &v1alpha2.SinkBinding{ ObjectMeta: metav1.ObjectMeta{ OwnerReferences: []metav1.OwnerReference{ *kmeta.NewControllerRef(source), @@ -84,7 +84,7 @@ func TestMakeSinkBinding(t *testing.T) { Name: fmt.Sprintf("%s-sinkbinding", source.Name), Namespace: source.Namespace, }, - Spec: v1alpha1.SinkBindingSpec{ + Spec: v1alpha2.SinkBindingSpec{ SourceSpec: source.Spec.SourceSpec, BindingSpec: duckv1alpha1.BindingSpec{ Subject: tracker.Reference{ From 7668afdc5eb2b645877bf18e388f95c5e2a966bc Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Thu, 26 Mar 2020 15:14:01 -0700 Subject: [PATCH 13/16] fixing e2e --- config/core/resources/containersource.yaml | 3 --- test/e2e/source_container_test.go | 4 ++-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/config/core/resources/containersource.yaml b/config/core/resources/containersource.yaml index 683c3f20121..8dd3709f9e7 100644 --- a/config/core/resources/containersource.yaml +++ b/config/core/resources/containersource.yaml @@ -57,9 +57,6 @@ spec: type: date JSONPath: .metadata.creationTimestamp versions: - - name: v1alpha1 - served: false - storage: false - name: v1alpha2 served: true storage: true diff --git a/test/e2e/source_container_test.go b/test/e2e/source_container_test.go index bf167830f08..1638a47c68f 100644 --- a/test/e2e/source_container_test.go +++ b/test/e2e/source_container_test.go @@ -31,7 +31,7 @@ import ( "knative.dev/eventing/test/lib" "knative.dev/eventing/test/lib/resources" - sourcesv1alpha1 "knative.dev/eventing/pkg/apis/sources/v1alpha1" + sourcesv1alpha2 "knative.dev/eventing/pkg/apis/sources/v1alpha2" eventingtesting "knative.dev/eventing/pkg/reconciler/testing" ) @@ -67,7 +67,7 @@ func TestContainerSource(t *testing.T) { containerSource := eventingtesting.NewContainerSource( containerSourceName, client.Namespace, - eventingtesting.WithContainerSourceSpec(sourcesv1alpha1.ContainerSourceSpec{ + eventingtesting.WithContainerSourceSpec(sourcesv1alpha2.ContainerSourceSpec{ Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ Name: templateName, From c8df7d9318d98eefb0ac6c7612be0a74de5a4b92 Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Thu, 26 Mar 2020 15:17:46 -0700 Subject: [PATCH 14/16] lint --- pkg/reconciler/containersource/containersource.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/reconciler/containersource/containersource.go b/pkg/reconciler/containersource/containersource.go index e308e5d081f..9486f0f6bc6 100644 --- a/pkg/reconciler/containersource/containersource.go +++ b/pkg/reconciler/containersource/containersource.go @@ -19,6 +19,7 @@ package containersource import ( "context" "fmt" + "go.uber.org/zap" appsv1 "k8s.io/api/apps/v1" From a0a0ae7748374109e585c0eb15ed8f5978c335ea Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Thu, 26 Mar 2020 15:25:02 -0700 Subject: [PATCH 15/16] fix e2e --- test/e2e/source_container_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/source_container_test.go b/test/e2e/source_container_test.go index 1638a47c68f..7efa32215ae 100644 --- a/test/e2e/source_container_test.go +++ b/test/e2e/source_container_test.go @@ -87,7 +87,7 @@ func TestContainerSource(t *testing.T) { }, }), ) - client.CreateContainerSourceV1Alpha1OrFail(containerSource) + client.CreateContainerSourceV1Alpha2OrFail(containerSource) // wait for all test resources to be ready client.WaitForAllTestResourcesReadyOrFail() From 73fdde67cccd36e84eb7f6be6dc932afb23099b1 Mon Sep 17 00:00:00 2001 From: Nacho Cano Date: Thu, 26 Mar 2020 15:25:19 -0700 Subject: [PATCH 16/16] comment --- test/lib/creation.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/lib/creation.go b/test/lib/creation.go index f27ddac8b27..c3c8cd7d1cf 100644 --- a/test/lib/creation.go +++ b/test/lib/creation.go @@ -301,10 +301,10 @@ func (client *Client) CreateApiServerSourceOrFail(apiServerSource *sourcesv1alph client.Tracker.AddObj(apiServerSource) } -// CreateContainerSourceV1Alpha1OrFail will create a ContainerSource. -func (client *Client) CreateContainerSourceV1Alpha1OrFail(containerSource *sourcesv1alpha1.ContainerSource) { +// CreateContainerSourceV1Alpha2OrFail will create a ContainerSource. +func (client *Client) CreateContainerSourceV1Alpha2OrFail(containerSource *sourcesv1alpha2.ContainerSource) { client.T.Logf("Creating containersource %+v", containerSource) - containerInterface := client.Eventing.SourcesV1alpha1().ContainerSources(client.Namespace) + containerInterface := client.Eventing.SourcesV1alpha2().ContainerSources(client.Namespace) _, err := containerInterface.Create(containerSource) if err != nil { client.T.Fatalf("Failed to create containersource %q: %v", containerSource.Name, err)