From b812a489c4d26fc3e1d562e40ef05875b749a0e6 Mon Sep 17 00:00:00 2001 From: XiyueYu Date: Thu, 16 Jul 2020 13:46:26 -0700 Subject: [PATCH 1/8] added v1beta1 apiserversource type --- .../sources/v1alpha2/apiserver_lifecycle.go | 2 +- .../sources/v1beta1/apiserver_conversion.go | 34 ++ .../v1beta1/apiserver_conversion_test.go | 34 ++ .../sources/v1beta1/apiserver_defaults.go | 36 ++ .../v1beta1/apiserver_defaults_test.go | 28 ++ .../sources/v1beta1/apiserver_lifecycle.go | 139 ++++++ .../v1beta1/apiserver_lifecycle_test.go | 326 +++++++++++++ pkg/apis/sources/v1beta1/apiserver_types.go | 161 +++++++ .../sources/v1beta1/apiserver_types_test.go | 36 ++ .../sources/v1beta1/apiserver_validation.go | 77 +++ .../v1beta1/apiserver_validation_test.go | 187 ++++++++ pkg/apis/sources/v1beta1/implements_test.go | 3 + pkg/apis/sources/v1beta1/register.go | 2 + pkg/apis/sources/v1beta1/register_test.go | 2 + .../sources/v1beta1/zz_generated.deepcopy.go | 145 ++++++ .../typed/sources/v1beta1/apiserversource.go | 191 ++++++++ .../v1beta1/fake/fake_apiserversource.go | 140 ++++++ .../v1beta1/fake/fake_sources_client.go | 4 + .../sources/v1beta1/generated_expansion.go | 2 + .../typed/sources/v1beta1/sources_client.go | 5 + .../informers/externalversions/generic.go | 2 + .../sources/v1beta1/apiserversource.go | 89 ++++ .../sources/v1beta1/interface.go | 7 + .../apiserversource/apiserversource.go | 52 ++ .../v1beta1/apiserversource/fake/fake.go | 40 ++ .../v1beta1/apiserversource/controller.go | 142 ++++++ .../v1beta1/apiserversource/reconciler.go | 448 ++++++++++++++++++ .../apiserversource/stub/controller.go | 54 +++ .../apiserversource/stub/reconciler.go | 87 ++++ .../sources/v1beta1/apiserversource.go | 94 ++++ .../sources/v1beta1/expansion_generated.go | 8 + 31 files changed, 2576 insertions(+), 1 deletion(-) create mode 100644 pkg/apis/sources/v1beta1/apiserver_conversion.go create mode 100644 pkg/apis/sources/v1beta1/apiserver_conversion_test.go create mode 100644 pkg/apis/sources/v1beta1/apiserver_defaults.go create mode 100644 pkg/apis/sources/v1beta1/apiserver_defaults_test.go create mode 100644 pkg/apis/sources/v1beta1/apiserver_lifecycle.go create mode 100644 pkg/apis/sources/v1beta1/apiserver_lifecycle_test.go create mode 100644 pkg/apis/sources/v1beta1/apiserver_types.go create mode 100644 pkg/apis/sources/v1beta1/apiserver_types_test.go create mode 100644 pkg/apis/sources/v1beta1/apiserver_validation.go create mode 100644 pkg/apis/sources/v1beta1/apiserver_validation_test.go create mode 100644 pkg/client/clientset/versioned/typed/sources/v1beta1/apiserversource.go create mode 100644 pkg/client/clientset/versioned/typed/sources/v1beta1/fake/fake_apiserversource.go create mode 100644 pkg/client/informers/externalversions/sources/v1beta1/apiserversource.go create mode 100644 pkg/client/injection/informers/sources/v1beta1/apiserversource/apiserversource.go create mode 100644 pkg/client/injection/informers/sources/v1beta1/apiserversource/fake/fake.go create mode 100644 pkg/client/injection/reconciler/sources/v1beta1/apiserversource/controller.go create mode 100644 pkg/client/injection/reconciler/sources/v1beta1/apiserversource/reconciler.go create mode 100644 pkg/client/injection/reconciler/sources/v1beta1/apiserversource/stub/controller.go create mode 100644 pkg/client/injection/reconciler/sources/v1beta1/apiserversource/stub/reconciler.go create mode 100644 pkg/client/listers/sources/v1beta1/apiserversource.go diff --git a/pkg/apis/sources/v1alpha2/apiserver_lifecycle.go b/pkg/apis/sources/v1alpha2/apiserver_lifecycle.go index d5c2b88eec2..4505c726b11 100644 --- a/pkg/apis/sources/v1alpha2/apiserver_lifecycle.go +++ b/pkg/apis/sources/v1alpha2/apiserver_lifecycle.go @@ -109,7 +109,7 @@ func (s *ApiServerSourceStatus) PropagateDeploymentAvailability(d *appsv1.Deploy } } if !deploymentAvailableFound { - PingSourceCondSet.Manage(s).MarkUnknown(PingSourceConditionDeployed, "DeploymentUnavailable", "The Deployment '%s' is unavailable.", d.Name) + apiserverCondSet.Manage(s).MarkUnknown(ApiServerConditionDeployed, "DeploymentUnavailable", "The Deployment '%s' is unavailable.", d.Name) } } diff --git a/pkg/apis/sources/v1beta1/apiserver_conversion.go b/pkg/apis/sources/v1beta1/apiserver_conversion.go new file mode 100644 index 00000000000..9003c4c6299 --- /dev/null +++ b/pkg/apis/sources/v1beta1/apiserver_conversion.go @@ -0,0 +1,34 @@ +/* +Copyright 2020 The Knative Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1beta1 + +import ( + "context" + "fmt" + + "knative.dev/pkg/apis" +) + +// ConvertTo implements apis.Convertible +func (source *ApiServerSource) ConvertTo(ctx context.Context, sink apis.Convertible) error { + return fmt.Errorf("v1beta1 is the highest known version, got: %T", sink) +} + +// ConvertFrom implements apis.Convertible +func (sink *ApiServerSource) ConvertFrom(ctx context.Context, source apis.Convertible) error { + return fmt.Errorf("v1beta1 is the highest known version, got: %T", source) +} diff --git a/pkg/apis/sources/v1beta1/apiserver_conversion_test.go b/pkg/apis/sources/v1beta1/apiserver_conversion_test.go new file mode 100644 index 00000000000..6a60fb1f048 --- /dev/null +++ b/pkg/apis/sources/v1beta1/apiserver_conversion_test.go @@ -0,0 +1,34 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1beta1 + +import ( + "context" + "testing" +) + +func TestApiServerConversionBadType(t *testing.T) { + good, bad := &ApiServerSource{}, &ApiServerSource{} + + if err := good.ConvertTo(context.Background(), bad); err == nil { + t.Errorf("ConvertTo() = %#v, wanted error", bad) + } + + if err := good.ConvertFrom(context.Background(), bad); err == nil { + t.Errorf("ConvertFrom() = %#v, wanted error", good) + } +} diff --git a/pkg/apis/sources/v1beta1/apiserver_defaults.go b/pkg/apis/sources/v1beta1/apiserver_defaults.go new file mode 100644 index 00000000000..31fcba4bcbc --- /dev/null +++ b/pkg/apis/sources/v1beta1/apiserver_defaults.go @@ -0,0 +1,36 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1beta1 + +import ( + "context" +) + +func (s *ApiServerSource) SetDefaults(ctx context.Context) { + s.Spec.SetDefaults(ctx) +} + +func (ss *ApiServerSourceSpec) SetDefaults(ctx context.Context) { + + if ss.EventMode == "" { + ss.EventMode = ReferenceMode + } + + if ss.ServiceAccountName == "" { + ss.ServiceAccountName = "default" + } +} diff --git a/pkg/apis/sources/v1beta1/apiserver_defaults_test.go b/pkg/apis/sources/v1beta1/apiserver_defaults_test.go new file mode 100644 index 00000000000..c11c427ef25 --- /dev/null +++ b/pkg/apis/sources/v1beta1/apiserver_defaults_test.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 v1beta1 + +import ( + "context" + "testing" +) + +// No-op test because method does nothing. +func TestAPIServerSourceDefaults(t *testing.T) { + s := ApiServerSource{} + s.SetDefaults(context.TODO()) +} diff --git a/pkg/apis/sources/v1beta1/apiserver_lifecycle.go b/pkg/apis/sources/v1beta1/apiserver_lifecycle.go new file mode 100644 index 00000000000..493c2c076a6 --- /dev/null +++ b/pkg/apis/sources/v1beta1/apiserver_lifecycle.go @@ -0,0 +1,139 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1beta1 + +import ( + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + + "knative.dev/pkg/apis" +) + +const ( + // ApiServerConditionReady has status True when the ApiServerSource is ready to send events. + ApiServerConditionReady = apis.ConditionReady + + // ApiServerConditionSinkProvided has status True when the ApiServerSource has been configured with a sink target. + ApiServerConditionSinkProvided apis.ConditionType = "SinkProvided" + + // ApiServerConditionDeployed has status True when the ApiServerSource has had it's deployment created. + ApiServerConditionDeployed apis.ConditionType = "Deployed" + + // ApiServerConditionSufficientPermissions has status True when the ApiServerSource has sufficient permissions to access resources. + ApiServerConditionSufficientPermissions apis.ConditionType = "SufficientPermissions" + + // ApiServerConditionEventTypeProvided has status True when the ApiServerSource has been configured with its event types. + ApiServerConditionEventTypeProvided apis.ConditionType = "EventTypesProvided" +) + +var apiserverCondSet = apis.NewLivingConditionSet( + ApiServerConditionSinkProvided, + ApiServerConditionDeployed, + ApiServerConditionSufficientPermissions, +) + +// GetConditionSet retrieves the condition set for this resource. Implements the KRShaped interface. +func (*ApiServerSource) GetConditionSet() apis.ConditionSet { + return apiserverCondSet +} + +// GetGroupVersionKind returns the GroupVersionKind. +func (*ApiServerSource) GetGroupVersionKind() schema.GroupVersionKind { + return SchemeGroupVersion.WithKind("ApiServerSource") +} + +// GetUntypedSpec returns the spec of the ApiServerSource. +func (s *ApiServerSource) GetUntypedSpec() interface{} { + return s.Spec +} + +// GetCondition returns the condition currently associated with the given type, or nil. +func (s *ApiServerSourceStatus) GetCondition(t apis.ConditionType) *apis.Condition { + return apiserverCondSet.Manage(s).GetCondition(t) +} + +// GetTopLevelCondition returns the top level condition. +func (s *ApiServerSourceStatus) GetTopLevelCondition() *apis.Condition { + return apiserverCondSet.Manage(s).GetTopLevelCondition() +} + +// InitializeConditions sets relevant unset conditions to Unknown state. +func (s *ApiServerSourceStatus) InitializeConditions() { + apiserverCondSet.Manage(s).InitializeConditions() +} + +// MarkSink sets the condition that the source has a sink configured. +func (s *ApiServerSourceStatus) MarkSink(uri *apis.URL) { + s.SinkURI = uri + if uri != nil { + apiserverCondSet.Manage(s).MarkTrue(ApiServerConditionSinkProvided) + } else { + apiserverCondSet.Manage(s).MarkFalse(ApiServerConditionSinkProvided, "SinkEmpty", "Sink has resolved to empty.%s", "") + } +} + +// MarkNoSink sets the condition that the source does not have a sink configured. +func (s *ApiServerSourceStatus) MarkNoSink(reason, messageFormat string, messageA ...interface{}) { + apiserverCondSet.Manage(s).MarkFalse(ApiServerConditionSinkProvided, reason, messageFormat, messageA...) +} + +// PropagateDeploymentAvailability uses the availability of the provided Deployment to determine if +// ApiServerConditionDeployed should be marked as true or false. +func (s *ApiServerSourceStatus) PropagateDeploymentAvailability(d *appsv1.Deployment) { + deploymentAvailableFound := false + for _, cond := range d.Status.Conditions { + if cond.Type == appsv1.DeploymentAvailable { + deploymentAvailableFound = true + if cond.Status == corev1.ConditionTrue { + apiserverCondSet.Manage(s).MarkTrue(ApiServerConditionDeployed) + } else if cond.Status == corev1.ConditionFalse { + apiserverCondSet.Manage(s).MarkFalse(ApiServerConditionDeployed, cond.Reason, cond.Message) + } else if cond.Status == corev1.ConditionUnknown { + apiserverCondSet.Manage(s).MarkUnknown(ApiServerConditionDeployed, cond.Reason, cond.Message) + } + } + } + if !deploymentAvailableFound { + apiserverCondSet.Manage(s).MarkUnknown(ApiServerConditionDeployed, "DeploymentUnavailable", "The Deployment '%s' is unavailable.", d.Name) + } +} + +// MarkEventTypes sets the condition that the source has set its event type. +func (s *ApiServerSourceStatus) MarkEventTypes() { + apiserverCondSet.Manage(s).MarkTrue(ApiServerConditionEventTypeProvided) +} + +// MarkNoEventTypes sets the condition that the source does not its event type configured. +func (s *ApiServerSourceStatus) MarkNoEventTypes(reason, messageFormat string, messageA ...interface{}) { + apiserverCondSet.Manage(s).MarkFalse(ApiServerConditionEventTypeProvided, reason, messageFormat, messageA...) +} + +// MarkSufficientPermissions sets the condition that the source has enough permissions to access the resources. +func (s *ApiServerSourceStatus) MarkSufficientPermissions() { + apiserverCondSet.Manage(s).MarkTrue(ApiServerConditionSufficientPermissions) +} + +// MarkNoSufficientPermissions sets the condition that the source does not have enough permissions to access the resources +func (s *ApiServerSourceStatus) MarkNoSufficientPermissions(reason, messageFormat string, messageA ...interface{}) { + apiserverCondSet.Manage(s).MarkFalse(ApiServerConditionSufficientPermissions, reason, messageFormat, messageA...) +} + +// IsReady returns true if the resource is ready overall. +func (s *ApiServerSourceStatus) IsReady() bool { + return apiserverCondSet.Manage(s).IsHappy() +} diff --git a/pkg/apis/sources/v1beta1/apiserver_lifecycle_test.go b/pkg/apis/sources/v1beta1/apiserver_lifecycle_test.go new file mode 100644 index 00000000000..8583e818ff7 --- /dev/null +++ b/pkg/apis/sources/v1beta1/apiserver_lifecycle_test.go @@ -0,0 +1,326 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1beta1 + +import ( + "reflect" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + "knative.dev/pkg/apis" +) + +func TestApiServerSourceGetConditionSet(t *testing.T) { + r := &ApiServerSource{} + + if got, want := r.GetConditionSet().GetTopLevelConditionType(), apis.ConditionReady; got != want { + t.Errorf("GetTopLevelCondition=%v, want=%v", got, want) + } +} + +func TestApiServerSourceGetGroupVersionKind(t *testing.T) { + r := &ApiServerSource{} + want := schema.GroupVersionKind{ + Group: "sources.knative.dev", + Version: "v1alpha2", + Kind: "ApiServerSource", + } + if got := r.GetGroupVersionKind(); got != want { + t.Errorf("got: %v, want: %v", got, want) + } +} + +func TestApiServerSourceStatusIsReady(t *testing.T) { + sink, _ := apis.ParseURL("uri://example") + + tests := []struct { + name string + s *ApiServerSourceStatus + wantConditionStatus corev1.ConditionStatus + want bool + }{{ + name: "uninitialized", + s: &ApiServerSourceStatus{}, + want: false, + }, { + name: "initialized", + s: func() *ApiServerSourceStatus { + s := &ApiServerSourceStatus{} + s.InitializeConditions() + return s + }(), + wantConditionStatus: corev1.ConditionUnknown, + want: false, + }, { + name: "mark deployed", + s: func() *ApiServerSourceStatus { + s := &ApiServerSourceStatus{} + s.InitializeConditions() + s.PropagateDeploymentAvailability(TestHelper.AvailableDeployment()) + return s + }(), + wantConditionStatus: corev1.ConditionUnknown, + want: false, + }, { + name: "mark sink", + s: func() *ApiServerSourceStatus { + s := &ApiServerSourceStatus{} + s.InitializeConditions() + s.MarkSink(sink) + return s + }(), + wantConditionStatus: corev1.ConditionUnknown, + want: false, + }, { + name: "mark sufficient permissions", + s: func() *ApiServerSourceStatus { + s := &ApiServerSourceStatus{} + s.InitializeConditions() + s.MarkSufficientPermissions() + return s + }(), + wantConditionStatus: corev1.ConditionUnknown, + want: false, + }, { + name: "mark event types", + s: func() *ApiServerSourceStatus { + s := &ApiServerSourceStatus{} + s.InitializeConditions() + s.MarkEventTypes() + return s + }(), + wantConditionStatus: corev1.ConditionUnknown, + want: false, + }, { + name: "mark sink and sufficient permissions and deployed", + s: func() *ApiServerSourceStatus { + s := &ApiServerSourceStatus{} + s.InitializeConditions() + s.MarkSink(sink) + s.MarkSufficientPermissions() + s.PropagateDeploymentAvailability(TestHelper.AvailableDeployment()) + return s + }(), + wantConditionStatus: corev1.ConditionTrue, + want: true, + }, { + name: "mark sink and sufficient permissions and unavailable deployment", + s: func() *ApiServerSourceStatus { + s := &ApiServerSourceStatus{} + s.InitializeConditions() + s.MarkSink(sink) + s.MarkSufficientPermissions() + s.PropagateDeploymentAvailability(TestHelper.UnavailableDeployment()) + return s + }(), + wantConditionStatus: corev1.ConditionFalse, + want: false, + }, { + name: "mark sink and sufficient permissions and unknown deployment", + s: func() *ApiServerSourceStatus { + s := &ApiServerSourceStatus{} + s.InitializeConditions() + s.MarkSink(sink) + s.MarkSufficientPermissions() + s.PropagateDeploymentAvailability(TestHelper.UnknownDeployment()) + return s + }(), + wantConditionStatus: corev1.ConditionUnknown, + want: false, + }, { + name: "mark sink and sufficient permissions and not deployed", + s: func() *ApiServerSourceStatus { + s := &ApiServerSourceStatus{} + s.InitializeConditions() + s.MarkSink(sink) + s.MarkSufficientPermissions() + s.PropagateDeploymentAvailability(&appsv1.Deployment{}) + return s + }(), + wantConditionStatus: corev1.ConditionUnknown, + want: false, + }, { + name: "mark sink and sufficient permissions and deployed and event types", + s: func() *ApiServerSourceStatus { + s := &ApiServerSourceStatus{} + s.InitializeConditions() + s.MarkSink(sink) + s.MarkSufficientPermissions() + s.PropagateDeploymentAvailability(TestHelper.AvailableDeployment()) + s.MarkEventTypes() + return s + }(), + wantConditionStatus: corev1.ConditionTrue, + want: true, + }, { + name: "mark sink and not enough permissions", + s: func() *ApiServerSourceStatus { + s := &ApiServerSourceStatus{} + s.InitializeConditions() + s.MarkSink(sink) + s.MarkNoSufficientPermissions("areason", "amessage") + return s + }(), + wantConditionStatus: corev1.ConditionFalse, + want: false, + }} + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + if test.wantConditionStatus != "" { + gotConditionStatus := test.s.GetTopLevelCondition().Status + if gotConditionStatus != test.wantConditionStatus { + t.Errorf("unexpected condition status: want %v, got %v", test.wantConditionStatus, gotConditionStatus) + } + } + got := test.s.IsReady() + if got != test.want { + t.Errorf("unexpected readiness: want %v, got %v", test.want, got) + } + }) + } +} + +func TestApiServerSourceStatusGetCondition(t *testing.T) { + sink, _ := apis.ParseURL("uri://example") + + tests := []struct { + name string + s *ApiServerSourceStatus + condQuery apis.ConditionType + want *apis.Condition + }{{ + name: "uninitialized", + s: &ApiServerSourceStatus{}, + condQuery: ApiServerConditionReady, + want: nil, + }, { + name: "initialized", + s: func() *ApiServerSourceStatus { + s := &ApiServerSourceStatus{} + s.InitializeConditions() + return s + }(), + condQuery: ApiServerConditionReady, + want: &apis.Condition{ + Type: ApiServerConditionReady, + Status: corev1.ConditionUnknown, + }, + }, { + name: "mark deployed", + s: func() *ApiServerSourceStatus { + s := &ApiServerSourceStatus{} + s.InitializeConditions() + s.PropagateDeploymentAvailability(TestHelper.AvailableDeployment()) + return s + }(), + condQuery: ApiServerConditionReady, + want: &apis.Condition{ + Type: ApiServerConditionReady, + Status: corev1.ConditionUnknown, + }, + }, { + name: "mark sink", + s: func() *ApiServerSourceStatus { + s := &ApiServerSourceStatus{} + s.InitializeConditions() + s.MarkSink(sink) + return s + }(), + condQuery: ApiServerConditionReady, + want: &apis.Condition{ + Type: ApiServerConditionReady, + Status: corev1.ConditionUnknown, + }, + }, { + name: "mark sink and enough permissions and deployed", + s: func() *ApiServerSourceStatus { + s := &ApiServerSourceStatus{} + s.InitializeConditions() + s.MarkSink(sink) + s.MarkSufficientPermissions() + s.PropagateDeploymentAvailability(TestHelper.AvailableDeployment()) + return s + }(), + condQuery: ApiServerConditionReady, + want: &apis.Condition{ + Type: ApiServerConditionReady, + Status: corev1.ConditionTrue, + }, + }, { + name: "mark sink and enough permissions and deployed and event types", + s: func() *ApiServerSourceStatus { + s := &ApiServerSourceStatus{} + s.InitializeConditions() + s.MarkSink(sink) + s.MarkSufficientPermissions() + s.PropagateDeploymentAvailability(TestHelper.AvailableDeployment()) + s.MarkEventTypes() + return s + }(), + condQuery: ApiServerConditionReady, + want: &apis.Condition{ + Type: ApiServerConditionReady, + Status: corev1.ConditionTrue, + }, + }, { + name: "mark sink empty and enough permissions and deployed and event types", + s: func() *ApiServerSourceStatus { + s := &ApiServerSourceStatus{} + s.InitializeConditions() + s.MarkSink(nil) + s.MarkSufficientPermissions() + s.PropagateDeploymentAvailability(TestHelper.AvailableDeployment()) + s.MarkEventTypes() + return s + }(), + condQuery: ApiServerConditionReady, + want: &apis.Condition{ + Type: ApiServerConditionReady, + Status: corev1.ConditionFalse, + Reason: "SinkEmpty", + Message: "Sink has resolved to empty.", + }, + }} + + 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) + } + }) + } +} + +func TestApiServerSourceGetters(t *testing.T) { + r := &ApiServerSource{ + Spec: ApiServerSourceSpec{ + ServiceAccountName: "test", + EventMode: "test", + }, + } + if got, want := r.GetUntypedSpec(), r.Spec; !reflect.DeepEqual(got, want) { + t.Errorf("GetUntypedSpec() = %v, want: %v", got, want) + } +} diff --git a/pkg/apis/sources/v1beta1/apiserver_types.go b/pkg/apis/sources/v1beta1/apiserver_types.go new file mode 100644 index 00000000000..7e338903096 --- /dev/null +++ b/pkg/apis/sources/v1beta1/apiserver_types.go @@ -0,0 +1,161 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1beta1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" + "knative.dev/pkg/kmeta" +) + +// +genclient +// +genreconciler +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +k8s:defaulter-gen=true + +// ApiServerSource is the Schema for the apiserversources API +type ApiServerSource struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec ApiServerSourceSpec `json:"spec,omitempty"` + Status ApiServerSourceStatus `json:"status,omitempty"` +} + +// Check the interfaces that ApiServerSource should be implementing. +var ( + _ runtime.Object = (*ApiServerSource)(nil) + _ kmeta.OwnerRefable = (*ApiServerSource)(nil) + _ apis.Validatable = (*ApiServerSource)(nil) + _ apis.Defaultable = (*ApiServerSource)(nil) + _ apis.HasSpec = (*ApiServerSource)(nil) + _ duckv1.KRShaped = (*ApiServerSource)(nil) +) + +const ( + // ApiServerSourceAddEventType is the ApiServerSource CloudEvent type for adds. + ApiServerSourceAddEventType = "dev.knative.apiserver.resource.add" + // ApiServerSourceUpdateEventType is the ApiServerSource CloudEvent type for updates. + ApiServerSourceUpdateEventType = "dev.knative.apiserver.resource.update" + // ApiServerSourceDeleteEventType is the ApiServerSource CloudEvent type for deletions. + ApiServerSourceDeleteEventType = "dev.knative.apiserver.resource.delete" + + // ApiServerSourceAddRefEventType is the ApiServerSource CloudEvent type for ref adds. + ApiServerSourceAddRefEventType = "dev.knative.apiserver.ref.add" + // ApiServerSourceUpdateRefEventType is the ApiServerSource CloudEvent type for ref updates. + ApiServerSourceUpdateRefEventType = "dev.knative.apiserver.ref.update" + // ApiServerSourceDeleteRefEventType is the ApiServerSource CloudEvent type for ref deletions. + ApiServerSourceDeleteRefEventType = "dev.knative.apiserver.ref.delete" +) + +// ApiServerSourceEventTypes is the list of CloudEvent types the ApiServerSource emits. +var ApiServerSourceEventTypes = []string{ + ApiServerSourceAddEventType, + ApiServerSourceDeleteEventType, + ApiServerSourceUpdateEventType, + ApiServerSourceAddRefEventType, + ApiServerSourceDeleteRefEventType, + ApiServerSourceUpdateRefEventType, +} + +// ApiServerSourceSpec defines the desired state of ApiServerSource +type ApiServerSourceSpec 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"` + + // Resource are the resources this source will track and send related + // lifecycle events from the Kubernetes ApiServer, with an optional label + // selector to help filter. + // +required + Resources []APIVersionKindSelector `json:"resources,omitempty"` + + // ResourceOwner is an additional filter to only track resources that are + // owned by a specific resource type. If ResourceOwner matches Resources[n] + // then Resources[n] is allowed to pass the ResourceOwner filter. + // +optional + ResourceOwner *APIVersionKind `json:"owner,omitempty"` + + // EventMode controls the format of the event. + // `Reference` sends a dataref event type for the resource under watch. + // `Resource` send the full resource lifecycle event. + // Defaults to `Reference` + // +optional + EventMode string `json:"mode,omitempty"` + + // ServiceAccountName is the name of the ServiceAccount to use to run this + // source. Defaults to default if not set. + // +optional + ServiceAccountName string `json:"serviceAccountName,omitempty"` +} + +// ApiServerSourceStatus defines the observed state of ApiServerSource +type ApiServerSourceStatus 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"` +} + +// APIVersionKind is an APIVersion and Kind tuple. +type APIVersionKind struct { + // APIVersion - the API version of the resource to watch. + APIVersion string `json:"apiVersion"` + + // Kind of the resource to watch. + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + Kind string `json:"kind"` +} + +// APIVersionKindSelector is an APIVersion Kind tuple with a LabelSelector. +type APIVersionKindSelector struct { + // APIVersion - the API version of the resource to watch. + APIVersion string `json:"apiVersion"` + + // Kind of the resource to watch. + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + Kind string `json:"kind"` + + // LabelSelector filters this source to objects to those resources pass the + // label selector. + // More info: http://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors + // +optional + LabelSelector *metav1.LabelSelector `json:"selector,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// ApiServerSourceList contains a list of ApiServerSource +type ApiServerSourceList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []ApiServerSource `json:"items"` +} + +// GetStatus retrieves the status of the ApiServerSource . Implements the KRShaped interface. +func (a *ApiServerSource) GetStatus() *duckv1.Status { + return &a.Status.Status +} diff --git a/pkg/apis/sources/v1beta1/apiserver_types_test.go b/pkg/apis/sources/v1beta1/apiserver_types_test.go new file mode 100644 index 00000000000..5ec67585b1f --- /dev/null +++ b/pkg/apis/sources/v1beta1/apiserver_types_test.go @@ -0,0 +1,36 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1beta1 + +import "testing" + +func TestApiServerSource_GetStatus(t *testing.T) { + r := &ApiServerSource{ + Status: ApiServerSourceStatus{}, + } + if got, want := r.GetStatus(), &r.Status.Status; got != want { + t.Errorf("GetStatus=%v, want=%v", got, want) + } +} + +func TestApiServerSource_GetGroupVersionKind(t *testing.T) { + ass := ApiServerSource{} + gvk := ass.GetGroupVersionKind() + if gvk.Kind != "ApiServerSource" { + t.Errorf("Should be ApiServerSource.") + } +} diff --git a/pkg/apis/sources/v1beta1/apiserver_validation.go b/pkg/apis/sources/v1beta1/apiserver_validation.go new file mode 100644 index 00000000000..97cb1d35d82 --- /dev/null +++ b/pkg/apis/sources/v1beta1/apiserver_validation.go @@ -0,0 +1,77 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1beta1 + +import ( + "context" + "strings" + + "k8s.io/apimachinery/pkg/runtime/schema" + + "knative.dev/pkg/apis" +) + +const ( + // ReferenceMode produces payloads of ObjectReference + ReferenceMode = "Reference" + // ResourceMode produces payloads of ResourceEvent + ResourceMode = "Resource" +) + +func (c *ApiServerSource) Validate(ctx context.Context) *apis.FieldError { + return c.Spec.Validate(ctx).ViaField("spec") +} + +func (cs *ApiServerSourceSpec) Validate(ctx context.Context) *apis.FieldError { + var errs *apis.FieldError + + // Validate mode, if can be empty or set as certain value + switch cs.EventMode { + case ReferenceMode, ResourceMode: + // EventMode is valid. + default: + errs = errs.Also(apis.ErrInvalidValue(cs.EventMode, "mode")) + } + + // Validate sink + errs = errs.Also(cs.Sink.Validate(ctx).ViaField("sink")) + + if len(cs.Resources) == 0 { + errs = errs.Also(apis.ErrMissingField("resources")) + } + for i, res := range cs.Resources { + _, err := schema.ParseGroupVersion(res.APIVersion) + if err != nil { + errs = errs.Also(apis.ErrInvalidValue(res.APIVersion, "apiVersion").ViaFieldIndex("resources", i)) + } + if strings.TrimSpace(res.Kind) == "" { + errs = errs.Also(apis.ErrMissingField("kind").ViaFieldIndex("resources", i)) + } + } + + if cs.ResourceOwner != nil { + _, err := schema.ParseGroupVersion(cs.ResourceOwner.APIVersion) + if err != nil { + errs = errs.Also(apis.ErrInvalidValue(cs.ResourceOwner.APIVersion, "apiVersion").ViaField("owner")) + } + if strings.TrimSpace(cs.ResourceOwner.Kind) == "" { + errs = errs.Also(apis.ErrMissingField("kind").ViaField("owner")) + } + } + + return errs +} diff --git a/pkg/apis/sources/v1beta1/apiserver_validation_test.go b/pkg/apis/sources/v1beta1/apiserver_validation_test.go new file mode 100644 index 00000000000..03ed0bcb589 --- /dev/null +++ b/pkg/apis/sources/v1beta1/apiserver_validation_test.go @@ -0,0 +1,187 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1beta1 + +import ( + "context" + "errors" + "testing" + + duckv1 "knative.dev/pkg/apis/duck/v1" + + "github.com/google/go-cmp/cmp" + "knative.dev/pkg/apis" +) + +func TestAPIServerValidation(t *testing.T) { + tests := []struct { + name string + spec ApiServerSourceSpec + want error + }{{ + name: "valid spec", + spec: ApiServerSourceSpec{ + EventMode: "Resource", + Resources: []APIVersionKindSelector{{ + APIVersion: "v1", + Kind: "Foo", + }}, + SourceSpec: duckv1.SourceSpec{ + Sink: duckv1.Destination{ + Ref: &duckv1.KReference{ + APIVersion: "v1alpha1", + Kind: "broker", + Name: "default", + }, + }, + }, + }, + want: nil, + }, { + name: "empty sink", + spec: ApiServerSourceSpec{ + EventMode: "Resource", + Resources: []APIVersionKindSelector{{ + APIVersion: "v1", + Kind: "Foo", + }}, + }, + want: func() *apis.FieldError { + var errs *apis.FieldError + errs = errs.Also(apis.ErrGeneric("expected at least one, got none", "ref", "uri").ViaField("sink")) + return errs + }(), + }, { + name: "invalid mode", + spec: ApiServerSourceSpec{ + EventMode: "Test", + Resources: []APIVersionKindSelector{{ + APIVersion: "v1", + Kind: "Foo", + }}, + SourceSpec: duckv1.SourceSpec{ + Sink: duckv1.Destination{ + Ref: &duckv1.KReference{ + APIVersion: "v1alpha1", + Kind: "broker", + Name: "default", + }, + }, + }, + }, + want: func() *apis.FieldError { + var errs *apis.FieldError + errs = errs.Also(apis.ErrInvalidValue("Test", "mode")) + return errs + }(), + }, { + name: "invalid apiVersion", + spec: ApiServerSourceSpec{ + EventMode: "Resource", + Resources: []APIVersionKindSelector{{ + APIVersion: "v1/v2/v3", + Kind: "Foo", + }}, + SourceSpec: duckv1.SourceSpec{ + Sink: duckv1.Destination{ + Ref: &duckv1.KReference{ + APIVersion: "v1alpha1", + Kind: "broker", + Name: "default", + }, + }, + }, + }, + want: errors.New("invalid value: v1/v2/v3: resources[0].apiVersion"), + }, { + name: "missing kind", + spec: ApiServerSourceSpec{ + EventMode: "Resource", + Resources: []APIVersionKindSelector{{ + APIVersion: "v1", + }}, + SourceSpec: duckv1.SourceSpec{ + Sink: duckv1.Destination{ + Ref: &duckv1.KReference{ + APIVersion: "v1alpha1", + Kind: "broker", + Name: "default", + }, + }, + }, + }, + want: errors.New("missing field(s): resources[0].kind"), + }, { + name: "owner - invalid apiVersion", + spec: ApiServerSourceSpec{ + EventMode: "Resource", + Resources: []APIVersionKindSelector{{ + APIVersion: "v1", + Kind: "Bar", + }}, + SourceSpec: duckv1.SourceSpec{ + Sink: duckv1.Destination{ + Ref: &duckv1.KReference{ + APIVersion: "v1alpha1", + Kind: "broker", + Name: "default", + }, + }, + }, + ResourceOwner: &APIVersionKind{ + APIVersion: "v1/v2/v3", + Kind: "Foo", + }, + }, + want: errors.New("invalid value: v1/v2/v3: owner.apiVersion"), + }, { + name: "missing kind", + spec: ApiServerSourceSpec{ + EventMode: "Resource", + Resources: []APIVersionKindSelector{{ + APIVersion: "v1", + Kind: "Bar", + }}, + SourceSpec: duckv1.SourceSpec{ + Sink: duckv1.Destination{ + Ref: &duckv1.KReference{ + APIVersion: "v1alpha1", + Kind: "broker", + Name: "default", + }, + }, + }, + ResourceOwner: &APIVersionKind{ + APIVersion: "v1", + }, + }, + want: errors.New("missing field(s): owner.kind"), + }} + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := test.spec.Validate(context.TODO()) + if test.want != nil { + if diff := cmp.Diff(test.want.Error(), got.Error()); diff != "" { + t.Errorf("APIServerSourceSpec.Validate (-want, +got) = %v", diff) + } + } else if got != nil { + t.Errorf("APIServerSourceSpec.Validate wanted nil, got = %v", got.Error()) + } + }) + } +} diff --git a/pkg/apis/sources/v1beta1/implements_test.go b/pkg/apis/sources/v1beta1/implements_test.go index ec618cf26f1..9e9f8209e6a 100644 --- a/pkg/apis/sources/v1beta1/implements_test.go +++ b/pkg/apis/sources/v1beta1/implements_test.go @@ -35,6 +35,9 @@ func TestTypesImplements(t *testing.T) { {instance: &SinkBinding{}, iface: &duckv1.Conditions{}}, {instance: &SinkBinding{}, iface: &duckv1.Source{}}, {instance: &SinkBinding{}, iface: &duckv1beta1.Binding{}}, + // ApiServerSource + {instance: &ApiServerSource{}, iface: &duckv1.Conditions{}}, + {instance: &ApiServerSource{}, iface: &duckv1.Source{}}, } for _, tc := range testCases { if err := duck.VerifyType(tc.instance, tc.iface); err != nil { diff --git a/pkg/apis/sources/v1beta1/register.go b/pkg/apis/sources/v1beta1/register.go index a4f6c6009e9..2fdbf9ccc58 100644 --- a/pkg/apis/sources/v1beta1/register.go +++ b/pkg/apis/sources/v1beta1/register.go @@ -45,6 +45,8 @@ var ( // Adds the list of known types to Scheme. func addKnownTypes(scheme *runtime.Scheme) error { scheme.AddKnownTypes(SchemeGroupVersion, + &ApiServerSource{}, + &ApiServerSourceList{}, &SinkBinding{}, &SinkBindingList{}, &ContainerSource{}, diff --git a/pkg/apis/sources/v1beta1/register_test.go b/pkg/apis/sources/v1beta1/register_test.go index cda3500e823..7a5790f453a 100644 --- a/pkg/apis/sources/v1beta1/register_test.go +++ b/pkg/apis/sources/v1beta1/register_test.go @@ -60,6 +60,8 @@ func TestKnownTypes(t *testing.T) { types := scheme.KnownTypes(SchemeGroupVersion) for _, name := range []string{ + "ApiServerSource", + "ApiServerSourceList", "SinkBinding", "SinkBindingList", "ContainerSource", diff --git a/pkg/apis/sources/v1beta1/zz_generated.deepcopy.go b/pkg/apis/sources/v1beta1/zz_generated.deepcopy.go index 22fa2c6ae8c..74fd3d497f3 100644 --- a/pkg/apis/sources/v1beta1/zz_generated.deepcopy.go +++ b/pkg/apis/sources/v1beta1/zz_generated.deepcopy.go @@ -21,9 +21,154 @@ limitations under the License. package v1beta1 import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" ) +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *APIVersionKind) DeepCopyInto(out *APIVersionKind) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new APIVersionKind. +func (in *APIVersionKind) DeepCopy() *APIVersionKind { + if in == nil { + return nil + } + out := new(APIVersionKind) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *APIVersionKindSelector) DeepCopyInto(out *APIVersionKindSelector) { + *out = *in + if in.LabelSelector != nil { + in, out := &in.LabelSelector, &out.LabelSelector + *out = new(v1.LabelSelector) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new APIVersionKindSelector. +func (in *APIVersionKindSelector) DeepCopy() *APIVersionKindSelector { + if in == nil { + return nil + } + out := new(APIVersionKindSelector) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ApiServerSource) DeepCopyInto(out *ApiServerSource) { + *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 ApiServerSource. +func (in *ApiServerSource) DeepCopy() *ApiServerSource { + if in == nil { + return nil + } + out := new(ApiServerSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ApiServerSource) 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 *ApiServerSourceList) DeepCopyInto(out *ApiServerSourceList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]ApiServerSource, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApiServerSourceList. +func (in *ApiServerSourceList) DeepCopy() *ApiServerSourceList { + if in == nil { + return nil + } + out := new(ApiServerSourceList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ApiServerSourceList) 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 *ApiServerSourceSpec) DeepCopyInto(out *ApiServerSourceSpec) { + *out = *in + in.SourceSpec.DeepCopyInto(&out.SourceSpec) + if in.Resources != nil { + in, out := &in.Resources, &out.Resources + *out = make([]APIVersionKindSelector, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.ResourceOwner != nil { + in, out := &in.ResourceOwner, &out.ResourceOwner + *out = new(APIVersionKind) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApiServerSourceSpec. +func (in *ApiServerSourceSpec) DeepCopy() *ApiServerSourceSpec { + if in == nil { + return nil + } + out := new(ApiServerSourceSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ApiServerSourceStatus) DeepCopyInto(out *ApiServerSourceStatus) { + *out = *in + in.SourceStatus.DeepCopyInto(&out.SourceStatus) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApiServerSourceStatus. +func (in *ApiServerSourceStatus) DeepCopy() *ApiServerSourceStatus { + if in == nil { + return nil + } + out := new(ApiServerSourceStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ContainerSource) DeepCopyInto(out *ContainerSource) { *out = *in diff --git a/pkg/client/clientset/versioned/typed/sources/v1beta1/apiserversource.go b/pkg/client/clientset/versioned/typed/sources/v1beta1/apiserversource.go new file mode 100644 index 00000000000..929886e32d3 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/sources/v1beta1/apiserversource.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 v1beta1 + +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" + v1beta1 "knative.dev/eventing/pkg/apis/sources/v1beta1" + scheme "knative.dev/eventing/pkg/client/clientset/versioned/scheme" +) + +// ApiServerSourcesGetter has a method to return a ApiServerSourceInterface. +// A group's client should implement this interface. +type ApiServerSourcesGetter interface { + ApiServerSources(namespace string) ApiServerSourceInterface +} + +// ApiServerSourceInterface has methods to work with ApiServerSource resources. +type ApiServerSourceInterface interface { + Create(*v1beta1.ApiServerSource) (*v1beta1.ApiServerSource, error) + Update(*v1beta1.ApiServerSource) (*v1beta1.ApiServerSource, error) + UpdateStatus(*v1beta1.ApiServerSource) (*v1beta1.ApiServerSource, error) + Delete(name string, options *v1.DeleteOptions) error + DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error + Get(name string, options v1.GetOptions) (*v1beta1.ApiServerSource, error) + List(opts v1.ListOptions) (*v1beta1.ApiServerSourceList, error) + Watch(opts v1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1beta1.ApiServerSource, err error) + ApiServerSourceExpansion +} + +// apiServerSources implements ApiServerSourceInterface +type apiServerSources struct { + client rest.Interface + ns string +} + +// newApiServerSources returns a ApiServerSources +func newApiServerSources(c *SourcesV1beta1Client, namespace string) *apiServerSources { + return &apiServerSources{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the apiServerSource, and returns the corresponding apiServerSource object, and an error if there is any. +func (c *apiServerSources) Get(name string, options v1.GetOptions) (result *v1beta1.ApiServerSource, err error) { + result = &v1beta1.ApiServerSource{} + err = c.client.Get(). + Namespace(c.ns). + Resource("apiserversources"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of ApiServerSources that match those selectors. +func (c *apiServerSources) List(opts v1.ListOptions) (result *v1beta1.ApiServerSourceList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1beta1.ApiServerSourceList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("apiserversources"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested apiServerSources. +func (c *apiServerSources) 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("apiserversources"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch() +} + +// Create takes the representation of a apiServerSource and creates it. Returns the server's representation of the apiServerSource, and an error, if there is any. +func (c *apiServerSources) Create(apiServerSource *v1beta1.ApiServerSource) (result *v1beta1.ApiServerSource, err error) { + result = &v1beta1.ApiServerSource{} + err = c.client.Post(). + Namespace(c.ns). + Resource("apiserversources"). + Body(apiServerSource). + Do(). + Into(result) + return +} + +// Update takes the representation of a apiServerSource and updates it. Returns the server's representation of the apiServerSource, and an error, if there is any. +func (c *apiServerSources) Update(apiServerSource *v1beta1.ApiServerSource) (result *v1beta1.ApiServerSource, err error) { + result = &v1beta1.ApiServerSource{} + err = c.client.Put(). + Namespace(c.ns). + Resource("apiserversources"). + Name(apiServerSource.Name). + Body(apiServerSource). + 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 *apiServerSources) UpdateStatus(apiServerSource *v1beta1.ApiServerSource) (result *v1beta1.ApiServerSource, err error) { + result = &v1beta1.ApiServerSource{} + err = c.client.Put(). + Namespace(c.ns). + Resource("apiserversources"). + Name(apiServerSource.Name). + SubResource("status"). + Body(apiServerSource). + Do(). + Into(result) + return +} + +// Delete takes name of the apiServerSource and deletes it. Returns an error if one occurs. +func (c *apiServerSources) Delete(name string, options *v1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("apiserversources"). + Name(name). + Body(options). + Do(). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *apiServerSources) 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("apiserversources"). + VersionedParams(&listOptions, scheme.ParameterCodec). + Timeout(timeout). + Body(options). + Do(). + Error() +} + +// Patch applies the patch and returns the patched apiServerSource. +func (c *apiServerSources) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1beta1.ApiServerSource, err error) { + result = &v1beta1.ApiServerSource{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("apiserversources"). + SubResource(subresources...). + Name(name). + Body(data). + Do(). + Into(result) + return +} diff --git a/pkg/client/clientset/versioned/typed/sources/v1beta1/fake/fake_apiserversource.go b/pkg/client/clientset/versioned/typed/sources/v1beta1/fake/fake_apiserversource.go new file mode 100644 index 00000000000..eebb4bda47b --- /dev/null +++ b/pkg/client/clientset/versioned/typed/sources/v1beta1/fake/fake_apiserversource.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" + v1beta1 "knative.dev/eventing/pkg/apis/sources/v1beta1" +) + +// FakeApiServerSources implements ApiServerSourceInterface +type FakeApiServerSources struct { + Fake *FakeSourcesV1beta1 + ns string +} + +var apiserversourcesResource = schema.GroupVersionResource{Group: "sources.knative.dev", Version: "v1beta1", Resource: "apiserversources"} + +var apiserversourcesKind = schema.GroupVersionKind{Group: "sources.knative.dev", Version: "v1beta1", Kind: "ApiServerSource"} + +// Get takes name of the apiServerSource, and returns the corresponding apiServerSource object, and an error if there is any. +func (c *FakeApiServerSources) Get(name string, options v1.GetOptions) (result *v1beta1.ApiServerSource, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(apiserversourcesResource, c.ns, name), &v1beta1.ApiServerSource{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.ApiServerSource), err +} + +// List takes label and field selectors, and returns the list of ApiServerSources that match those selectors. +func (c *FakeApiServerSources) List(opts v1.ListOptions) (result *v1beta1.ApiServerSourceList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(apiserversourcesResource, apiserversourcesKind, c.ns, opts), &v1beta1.ApiServerSourceList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1beta1.ApiServerSourceList{ListMeta: obj.(*v1beta1.ApiServerSourceList).ListMeta} + for _, item := range obj.(*v1beta1.ApiServerSourceList).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 apiServerSources. +func (c *FakeApiServerSources) Watch(opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(apiserversourcesResource, c.ns, opts)) + +} + +// Create takes the representation of a apiServerSource and creates it. Returns the server's representation of the apiServerSource, and an error, if there is any. +func (c *FakeApiServerSources) Create(apiServerSource *v1beta1.ApiServerSource) (result *v1beta1.ApiServerSource, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(apiserversourcesResource, c.ns, apiServerSource), &v1beta1.ApiServerSource{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.ApiServerSource), err +} + +// Update takes the representation of a apiServerSource and updates it. Returns the server's representation of the apiServerSource, and an error, if there is any. +func (c *FakeApiServerSources) Update(apiServerSource *v1beta1.ApiServerSource) (result *v1beta1.ApiServerSource, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(apiserversourcesResource, c.ns, apiServerSource), &v1beta1.ApiServerSource{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.ApiServerSource), 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 *FakeApiServerSources) UpdateStatus(apiServerSource *v1beta1.ApiServerSource) (*v1beta1.ApiServerSource, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(apiserversourcesResource, "status", c.ns, apiServerSource), &v1beta1.ApiServerSource{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.ApiServerSource), err +} + +// Delete takes name of the apiServerSource and deletes it. Returns an error if one occurs. +func (c *FakeApiServerSources) Delete(name string, options *v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteAction(apiserversourcesResource, c.ns, name), &v1beta1.ApiServerSource{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeApiServerSources) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(apiserversourcesResource, c.ns, listOptions) + + _, err := c.Fake.Invokes(action, &v1beta1.ApiServerSourceList{}) + return err +} + +// Patch applies the patch and returns the patched apiServerSource. +func (c *FakeApiServerSources) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1beta1.ApiServerSource, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(apiserversourcesResource, c.ns, name, pt, data, subresources...), &v1beta1.ApiServerSource{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.ApiServerSource), err +} diff --git a/pkg/client/clientset/versioned/typed/sources/v1beta1/fake/fake_sources_client.go b/pkg/client/clientset/versioned/typed/sources/v1beta1/fake/fake_sources_client.go index bcae6657420..9ea481b5db5 100644 --- a/pkg/client/clientset/versioned/typed/sources/v1beta1/fake/fake_sources_client.go +++ b/pkg/client/clientset/versioned/typed/sources/v1beta1/fake/fake_sources_client.go @@ -28,6 +28,10 @@ type FakeSourcesV1beta1 struct { *testing.Fake } +func (c *FakeSourcesV1beta1) ApiServerSources(namespace string) v1beta1.ApiServerSourceInterface { + return &FakeApiServerSources{c, namespace} +} + func (c *FakeSourcesV1beta1) ContainerSources(namespace string) v1beta1.ContainerSourceInterface { return &FakeContainerSources{c, namespace} } diff --git a/pkg/client/clientset/versioned/typed/sources/v1beta1/generated_expansion.go b/pkg/client/clientset/versioned/typed/sources/v1beta1/generated_expansion.go index 3f1743bd045..e42f4bcb3df 100644 --- a/pkg/client/clientset/versioned/typed/sources/v1beta1/generated_expansion.go +++ b/pkg/client/clientset/versioned/typed/sources/v1beta1/generated_expansion.go @@ -18,6 +18,8 @@ limitations under the License. package v1beta1 +type ApiServerSourceExpansion interface{} + type ContainerSourceExpansion interface{} type SinkBindingExpansion interface{} diff --git a/pkg/client/clientset/versioned/typed/sources/v1beta1/sources_client.go b/pkg/client/clientset/versioned/typed/sources/v1beta1/sources_client.go index a38c2341a51..576f4d5b6cd 100644 --- a/pkg/client/clientset/versioned/typed/sources/v1beta1/sources_client.go +++ b/pkg/client/clientset/versioned/typed/sources/v1beta1/sources_client.go @@ -26,6 +26,7 @@ import ( type SourcesV1beta1Interface interface { RESTClient() rest.Interface + ApiServerSourcesGetter ContainerSourcesGetter SinkBindingsGetter } @@ -35,6 +36,10 @@ type SourcesV1beta1Client struct { restClient rest.Interface } +func (c *SourcesV1beta1Client) ApiServerSources(namespace string) ApiServerSourceInterface { + return newApiServerSources(c, namespace) +} + func (c *SourcesV1beta1Client) ContainerSources(namespace string) ContainerSourceInterface { return newContainerSources(c, namespace) } diff --git a/pkg/client/informers/externalversions/generic.go b/pkg/client/informers/externalversions/generic.go index dd7913ca0b5..e969775f8bc 100644 --- a/pkg/client/informers/externalversions/generic.go +++ b/pkg/client/informers/externalversions/generic.go @@ -126,6 +126,8 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource return &genericInformer{resource: resource.GroupResource(), informer: f.Sources().V1alpha2().SinkBindings().Informer()}, nil // Group=sources.knative.dev, Version=v1beta1 + case sourcesv1beta1.SchemeGroupVersion.WithResource("apiserversources"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Sources().V1beta1().ApiServerSources().Informer()}, nil case sourcesv1beta1.SchemeGroupVersion.WithResource("containersources"): return &genericInformer{resource: resource.GroupResource(), informer: f.Sources().V1beta1().ContainerSources().Informer()}, nil case sourcesv1beta1.SchemeGroupVersion.WithResource("sinkbindings"): diff --git a/pkg/client/informers/externalversions/sources/v1beta1/apiserversource.go b/pkg/client/informers/externalversions/sources/v1beta1/apiserversource.go new file mode 100644 index 00000000000..05e8febc2e4 --- /dev/null +++ b/pkg/client/informers/externalversions/sources/v1beta1/apiserversource.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 v1beta1 + +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" + sourcesv1beta1 "knative.dev/eventing/pkg/apis/sources/v1beta1" + versioned "knative.dev/eventing/pkg/client/clientset/versioned" + internalinterfaces "knative.dev/eventing/pkg/client/informers/externalversions/internalinterfaces" + v1beta1 "knative.dev/eventing/pkg/client/listers/sources/v1beta1" +) + +// ApiServerSourceInformer provides access to a shared informer and lister for +// ApiServerSources. +type ApiServerSourceInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1beta1.ApiServerSourceLister +} + +type apiServerSourceInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewApiServerSourceInformer constructs a new informer for ApiServerSource 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 NewApiServerSourceInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredApiServerSourceInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredApiServerSourceInformer constructs a new informer for ApiServerSource 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 NewFilteredApiServerSourceInformer(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.SourcesV1beta1().ApiServerSources(namespace).List(options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.SourcesV1beta1().ApiServerSources(namespace).Watch(options) + }, + }, + &sourcesv1beta1.ApiServerSource{}, + resyncPeriod, + indexers, + ) +} + +func (f *apiServerSourceInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredApiServerSourceInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *apiServerSourceInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&sourcesv1beta1.ApiServerSource{}, f.defaultInformer) +} + +func (f *apiServerSourceInformer) Lister() v1beta1.ApiServerSourceLister { + return v1beta1.NewApiServerSourceLister(f.Informer().GetIndexer()) +} diff --git a/pkg/client/informers/externalversions/sources/v1beta1/interface.go b/pkg/client/informers/externalversions/sources/v1beta1/interface.go index b6867f102b9..90247203d83 100644 --- a/pkg/client/informers/externalversions/sources/v1beta1/interface.go +++ b/pkg/client/informers/externalversions/sources/v1beta1/interface.go @@ -24,6 +24,8 @@ import ( // Interface provides access to all the informers in this group version. type Interface interface { + // ApiServerSources returns a ApiServerSourceInformer. + ApiServerSources() ApiServerSourceInformer // ContainerSources returns a ContainerSourceInformer. ContainerSources() ContainerSourceInformer // SinkBindings returns a SinkBindingInformer. @@ -41,6 +43,11 @@ func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakList return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} } +// ApiServerSources returns a ApiServerSourceInformer. +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} diff --git a/pkg/client/injection/informers/sources/v1beta1/apiserversource/apiserversource.go b/pkg/client/injection/informers/sources/v1beta1/apiserversource/apiserversource.go new file mode 100644 index 00000000000..f39cd81053d --- /dev/null +++ b/pkg/client/injection/informers/sources/v1beta1/apiserversource/apiserversource.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 apiserversource + +import ( + context "context" + + v1beta1 "knative.dev/eventing/pkg/client/informers/externalversions/sources/v1beta1" + 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().V1beta1().ApiServerSources() + return context.WithValue(ctx, Key{}, inf), inf.Informer() +} + +// Get extracts the typed informer from the context. +func Get(ctx context.Context) v1beta1.ApiServerSourceInformer { + untyped := ctx.Value(Key{}) + if untyped == nil { + logging.FromContext(ctx).Panic( + "Unable to fetch knative.dev/eventing/pkg/client/informers/externalversions/sources/v1beta1.ApiServerSourceInformer from context.") + } + return untyped.(v1beta1.ApiServerSourceInformer) +} diff --git a/pkg/client/injection/informers/sources/v1beta1/apiserversource/fake/fake.go b/pkg/client/injection/informers/sources/v1beta1/apiserversource/fake/fake.go new file mode 100644 index 00000000000..cd678ab7200 --- /dev/null +++ b/pkg/client/injection/informers/sources/v1beta1/apiserversource/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" + apiserversource "knative.dev/eventing/pkg/client/injection/informers/sources/v1beta1/apiserversource" + controller "knative.dev/pkg/controller" + injection "knative.dev/pkg/injection" +) + +var Get = apiserversource.Get + +func init() { + injection.Fake.RegisterInformer(withInformer) +} + +func withInformer(ctx context.Context) (context.Context, controller.Informer) { + f := fake.Get(ctx) + inf := f.Sources().V1beta1().ApiServerSources() + return context.WithValue(ctx, apiserversource.Key{}, inf), inf.Informer() +} diff --git a/pkg/client/injection/reconciler/sources/v1beta1/apiserversource/controller.go b/pkg/client/injection/reconciler/sources/v1beta1/apiserversource/controller.go new file mode 100644 index 00000000000..5bf729d06ab --- /dev/null +++ b/pkg/client/injection/reconciler/sources/v1beta1/apiserversource/controller.go @@ -0,0 +1,142 @@ +/* +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 apiserversource + +import ( + context "context" + fmt "fmt" + reflect "reflect" + strings "strings" + + corev1 "k8s.io/api/core/v1" + labels "k8s.io/apimachinery/pkg/labels" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + scheme "k8s.io/client-go/kubernetes/scheme" + v1 "k8s.io/client-go/kubernetes/typed/core/v1" + record "k8s.io/client-go/tools/record" + versionedscheme "knative.dev/eventing/pkg/client/clientset/versioned/scheme" + client "knative.dev/eventing/pkg/client/injection/client" + apiserversource "knative.dev/eventing/pkg/client/injection/informers/sources/v1beta1/apiserversource" + kubeclient "knative.dev/pkg/client/injection/kube/client" + controller "knative.dev/pkg/controller" + logging "knative.dev/pkg/logging" + reconciler "knative.dev/pkg/reconciler" +) + +const ( + defaultControllerAgentName = "apiserversource-controller" + defaultFinalizerName = "apiserversources.sources.knative.dev" +) + +// NewImpl returns a controller.Impl that handles queuing and feeding work from +// the queue through an implementation of controller.Reconciler, delegating to +// the provided Interface and optional Finalizer methods. OptionsFn is used to return +// controller.Options to be used but the internal reconciler. +func NewImpl(ctx context.Context, r Interface, optionsFns ...controller.OptionsFn) *controller.Impl { + logger := logging.FromContext(ctx) + + // Check the options function input. It should be 0 or 1. + if len(optionsFns) > 1 { + logger.Fatalf("up to one options function is supported, found %d", len(optionsFns)) + } + + apiserversourceInformer := apiserversource.Get(ctx) + + lister := apiserversourceInformer.Lister() + + rec := &reconcilerImpl{ + LeaderAwareFuncs: reconciler.LeaderAwareFuncs{ + PromoteFunc: func(bkt reconciler.Bucket, enq func(reconciler.Bucket, types.NamespacedName)) error { + all, err := lister.List(labels.Everything()) + if err != nil { + return err + } + for _, elt := range all { + // TODO: Consider letting users specify a filter in options. + enq(bkt, types.NamespacedName{ + Namespace: elt.GetNamespace(), + Name: elt.GetName(), + }) + } + return nil + }, + }, + Client: client.Get(ctx), + Lister: lister, + reconciler: r, + finalizerName: defaultFinalizerName, + } + + t := reflect.TypeOf(r).Elem() + queueName := fmt.Sprintf("%s.%s", strings.ReplaceAll(t.PkgPath(), "/", "-"), t.Name()) + + impl := controller.NewImpl(rec, logger, queueName) + agentName := defaultControllerAgentName + + // Pass impl to the options. Save any optional results. + for _, fn := range optionsFns { + opts := fn(impl) + if opts.ConfigStore != nil { + rec.configStore = opts.ConfigStore + } + if opts.FinalizerName != "" { + rec.finalizerName = opts.FinalizerName + } + if opts.AgentName != "" { + agentName = opts.AgentName + } + if opts.SkipStatusUpdates { + rec.skipStatusUpdates = true + } + } + + rec.Recorder = createRecorder(ctx, agentName) + + return impl +} + +func createRecorder(ctx context.Context, agentName string) record.EventRecorder { + logger := logging.FromContext(ctx) + + recorder := controller.GetEventRecorder(ctx) + if recorder == nil { + // Create event broadcaster + logger.Debug("Creating event broadcaster") + eventBroadcaster := record.NewBroadcaster() + watches := []watch.Interface{ + eventBroadcaster.StartLogging(logger.Named("event-broadcaster").Infof), + eventBroadcaster.StartRecordingToSink( + &v1.EventSinkImpl{Interface: kubeclient.Get(ctx).CoreV1().Events("")}), + } + recorder = eventBroadcaster.NewRecorder(scheme.Scheme, corev1.EventSource{Component: agentName}) + go func() { + <-ctx.Done() + for _, w := range watches { + w.Stop() + } + }() + } + + return recorder +} + +func init() { + versionedscheme.AddToScheme(scheme.Scheme) +} diff --git a/pkg/client/injection/reconciler/sources/v1beta1/apiserversource/reconciler.go b/pkg/client/injection/reconciler/sources/v1beta1/apiserversource/reconciler.go new file mode 100644 index 00000000000..02f4e325599 --- /dev/null +++ b/pkg/client/injection/reconciler/sources/v1beta1/apiserversource/reconciler.go @@ -0,0 +1,448 @@ +/* +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 apiserversource + +import ( + context "context" + json "encoding/json" + fmt "fmt" + reflect "reflect" + + zap "go.uber.org/zap" + v1 "k8s.io/api/core/v1" + equality "k8s.io/apimachinery/pkg/api/equality" + errors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + types "k8s.io/apimachinery/pkg/types" + sets "k8s.io/apimachinery/pkg/util/sets" + cache "k8s.io/client-go/tools/cache" + record "k8s.io/client-go/tools/record" + v1beta1 "knative.dev/eventing/pkg/apis/sources/v1beta1" + versioned "knative.dev/eventing/pkg/client/clientset/versioned" + sourcesv1beta1 "knative.dev/eventing/pkg/client/listers/sources/v1beta1" + 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 v1beta1.ApiServerSource. +type Interface interface { + // ReconcileKind implements custom logic to reconcile v1beta1.ApiServerSource. 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 *v1beta1.ApiServerSource) reconciler.Event +} + +// Finalizer defines the strongly typed interfaces to be implemented by a +// controller finalizing v1beta1.ApiServerSource. +type Finalizer interface { + // FinalizeKind implements custom logic to finalize v1beta1.ApiServerSource. 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 *v1beta1.ApiServerSource) reconciler.Event +} + +// ReadOnlyInterface defines the strongly typed interfaces to be implemented by a +// controller reconciling v1beta1.ApiServerSource if they want to process resources for which +// they are not the leader. +type ReadOnlyInterface interface { + // ObserveKind implements logic to observe v1beta1.ApiServerSource. + // This method should not write to the API. + ObserveKind(ctx context.Context, o *v1beta1.ApiServerSource) reconciler.Event +} + +// ReadOnlyFinalizer defines the strongly typed interfaces to be implemented by a +// controller finalizing v1beta1.ApiServerSource if they want to process tombstoned resources +// even when they are not the leader. Due to the nature of how finalizers are handled +// there are no guarantees that this will be called. +type ReadOnlyFinalizer interface { + // ObserveFinalizeKind implements custom logic to observe the final state of v1beta1.ApiServerSource. + // This method should not write to the API. + ObserveFinalizeKind(ctx context.Context, o *v1beta1.ApiServerSource) reconciler.Event +} + +// reconcilerImpl implements controller.Reconciler for v1beta1.ApiServerSource resources. +type reconcilerImpl struct { + // LeaderAwareFuncs is inlined to help us implement reconciler.LeaderAware + reconciler.LeaderAwareFuncs + + // Client is used to write back status updates. + Client versioned.Interface + + // Listers index properties about resources + Lister sourcesv1beta1.ApiServerSourceLister + + // Recorder is an event recorder for recording Event resources to the + // Kubernetes API. + Recorder record.EventRecorder + + // configStore allows for decorating a context with config maps. + // +optional + configStore reconciler.ConfigStore + + // reconciler is the implementation of the business logic of the resource. + reconciler Interface + + // finalizerName is the name of the finalizer to reconcile. + finalizerName string + + // skipStatusUpdates configures whether or not this reconciler automatically updates + // the status of the reconciled resource. + skipStatusUpdates bool +} + +// Check that our Reconciler implements controller.Reconciler +var _ controller.Reconciler = (*reconcilerImpl)(nil) + +// Check that our generated Reconciler is always LeaderAware. +var _ reconciler.LeaderAware = (*reconcilerImpl)(nil) + +func NewReconciler(ctx context.Context, logger *zap.SugaredLogger, client versioned.Interface, lister sourcesv1beta1.ApiServerSourceLister, recorder record.EventRecorder, r Interface, options ...controller.Options) controller.Reconciler { + // Check the options function input. It should be 0 or 1. + if len(options) > 1 { + logger.Fatalf("up to one options struct is supported, found %d", len(options)) + } + + // Fail fast when users inadvertently implement the other LeaderAware interface. + // For the typed reconcilers, Promote shouldn't take any arguments. + if _, ok := r.(reconciler.LeaderAware); ok { + logger.Fatalf("%T implements the incorrect LeaderAware interface. Promote() should not take an argument as genreconciler handles the enqueuing automatically.", r) + } + // TODO: Consider validating when folks implement ReadOnlyFinalizer, but not Finalizer. + + rec := &reconcilerImpl{ + LeaderAwareFuncs: reconciler.LeaderAwareFuncs{ + PromoteFunc: func(bkt reconciler.Bucket, enq func(reconciler.Bucket, types.NamespacedName)) error { + all, err := lister.List(labels.Everything()) + if err != nil { + return err + } + for _, elt := range all { + // TODO: Consider letting users specify a filter in options. + enq(bkt, types.NamespacedName{ + Namespace: elt.GetNamespace(), + Name: elt.GetName(), + }) + } + return nil + }, + }, + Client: client, + Lister: lister, + Recorder: recorder, + reconciler: r, + finalizerName: defaultFinalizerName, + } + + for _, opts := range options { + if opts.ConfigStore != nil { + rec.configStore = opts.ConfigStore + } + if opts.FinalizerName != "" { + rec.finalizerName = opts.FinalizerName + } + if opts.SkipStatusUpdates { + rec.skipStatusUpdates = true + } + } + + return rec +} + +// Reconcile implements controller.Reconciler +func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { + logger := logging.FromContext(ctx) + + // Convert the namespace/name string into a distinct namespace and name + namespace, name, err := cache.SplitMetaNamespaceKey(key) + if err != nil { + logger.Errorf("invalid resource key: %s", key) + return nil + } + // Establish whether we are the leader for use below. + isLeader := r.IsLeaderFor(types.NamespacedName{ + Namespace: namespace, + Name: name, + }) + roi, isROI := r.reconciler.(ReadOnlyInterface) + rof, isROF := r.reconciler.(ReadOnlyFinalizer) + if !isLeader && !isROI && !isROF { + // If we are not the leader, and we don't implement either ReadOnly + // interface, then take a fast-path out. + return nil + } + + // If configStore is set, attach the frozen configuration to the context. + if r.configStore != nil { + ctx = r.configStore.ToContext(ctx) + } + + // Add the recorder to context. + ctx = controller.WithEventRecorder(ctx, r.Recorder) + + // Get the resource with this namespace/name. + + getter := r.Lister.ApiServerSources(namespace) + + original, err := getter.Get(name) + + if errors.IsNotFound(err) { + // The resource may no longer exist, in which case we stop processing. + logger.Debugf("resource %q no longer exists", key) + return nil + } else if err != nil { + return err + } + + // Don't modify the informers copy. + resource := original.DeepCopy() + + var reconcileEvent reconciler.Event + if resource.GetDeletionTimestamp().IsZero() { + if isLeader { + // Append the target method to the logger. + logger = logger.With(zap.String("targetMethod", "ReconcileKind")) + + // Set and update the finalizer on resource if r.reconciler + // implements Finalizer. + if resource, err = r.setFinalizerIfFinalizer(ctx, resource); err != nil { + return fmt.Errorf("failed to set finalizers: %w", err) + } + + reconciler.PreProcessReconcile(ctx, resource) + + // Reconcile this copy of the resource and then write back any status + // updates regardless of whether the reconciliation errored out. + reconcileEvent = r.reconciler.ReconcileKind(ctx, resource) + + reconciler.PostProcessReconcile(ctx, resource, original) + + } else if isROI { + // Append the target method to the logger. + logger = logger.With(zap.String("targetMethod", "ObserveKind")) + + // Observe any changes to this resource, since we are not the leader. + reconcileEvent = roi.ObserveKind(ctx, resource) + } + } else if fin, ok := r.reconciler.(Finalizer); isLeader && ok { + // Append the target method to the logger. + logger = logger.With(zap.String("targetMethod", "FinalizeKind")) + + // For finalizing reconcilers, if this resource being marked for deletion + // and reconciled cleanly (nil or normal event), remove the finalizer. + reconcileEvent = fin.FinalizeKind(ctx, resource) + if resource, err = r.clearFinalizer(ctx, resource, reconcileEvent); err != nil { + return fmt.Errorf("failed to clear finalizers: %w", err) + } + } else if !isLeader && isROF { + // Append the target method to the logger. + logger = logger.With(zap.String("targetMethod", "ObserveFinalizeKind")) + + // For finalizing reconcilers, just observe when we aren't the leader. + reconcileEvent = rof.ObserveFinalizeKind(ctx, resource) + } + + // Synchronize the status. + switch { + case r.skipStatusUpdates: + // This reconciler implementation is configured to skip resource updates. + // This may mean this reconciler does not observe spec, but reconciles external changes. + case 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. + case !isLeader: + // High-availability reconcilers may have many replicas watching the resource, but only + // the elected leader is expected to write modifications. + logger.Warn("Saw status changes when we aren't the leader!") + default: + 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...) + + // the event was wrapped inside an error, consider the reconciliation as failed + if _, isEvent := reconcileEvent.(*reconciler.ReconcilerEvent); !isEvent { + return reconcileEvent + } + return nil + } + + logger.Errorw("Returned an error", zap.Error(reconcileEvent)) + r.Recorder.Event(resource, v1.EventTypeWarning, "InternalError", reconcileEvent.Error()) + return reconcileEvent + } + + return nil +} + +func (r *reconcilerImpl) updateStatus(existing *v1beta1.ApiServerSource, desired *v1beta1.ApiServerSource) 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.SourcesV1beta1().ApiServerSources(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.SourcesV1beta1().ApiServerSources(existing.Namespace) + + _, err = updater.UpdateStatus(existing) + return err + }) +} + +// updateFinalizersFiltered will update the Finalizers of the resource. +// TODO: this method could be generic and sync all finalizers. For now it only +// updates defaultFinalizerName or its override. +func (r *reconcilerImpl) updateFinalizersFiltered(ctx context.Context, resource *v1beta1.ApiServerSource) (*v1beta1.ApiServerSource, error) { + + getter := r.Lister.ApiServerSources(resource.Namespace) + + actual, err := getter.Get(resource.Name) + if err != nil { + return resource, err + } + + // Don't modify the informers copy. + existing := actual.DeepCopy() + + var finalizers []string + + // If there's nothing to update, just return. + existingFinalizers := sets.NewString(existing.Finalizers...) + desiredFinalizers := sets.NewString(resource.Finalizers...) + + if desiredFinalizers.Has(r.finalizerName) { + if existingFinalizers.Has(r.finalizerName) { + // Nothing to do. + return resource, nil + } + // Add the finalizer. + finalizers = append(existing.Finalizers, r.finalizerName) + } else { + if !existingFinalizers.Has(r.finalizerName) { + // Nothing to do. + return resource, nil + } + // Remove the finalizer. + existingFinalizers.Delete(r.finalizerName) + finalizers = existingFinalizers.List() + } + + mergePatch := map[string]interface{}{ + "metadata": map[string]interface{}{ + "finalizers": finalizers, + "resourceVersion": existing.ResourceVersion, + }, + } + + patch, err := json.Marshal(mergePatch) + if err != nil { + return resource, err + } + + patcher := r.Client.SourcesV1beta1().ApiServerSources(resource.Namespace) + + resourceName := resource.Name + resource, err = patcher.Patch(resourceName, types.MergePatchType, patch) + if err != nil { + r.Recorder.Eventf(resource, v1.EventTypeWarning, "FinalizerUpdateFailed", + "Failed to update finalizers for %q: %v", resourceName, 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 *v1beta1.ApiServerSource) (*v1beta1.ApiServerSource, error) { + if _, ok := r.reconciler.(Finalizer); !ok { + return resource, nil + } + + finalizers := sets.NewString(resource.Finalizers...) + + // If this resource is not being deleted, mark the finalizer. + if resource.GetDeletionTimestamp().IsZero() { + finalizers.Insert(r.finalizerName) + } + + resource.Finalizers = finalizers.List() + + // Synchronize the finalizers filtered by r.finalizerName. + return r.updateFinalizersFiltered(ctx, resource) +} + +func (r *reconcilerImpl) clearFinalizer(ctx context.Context, resource *v1beta1.ApiServerSource, reconcileEvent reconciler.Event) (*v1beta1.ApiServerSource, 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(r.finalizerName) + } + } + } else { + finalizers.Delete(r.finalizerName) + } + + resource.Finalizers = finalizers.List() + + // Synchronize the finalizers filtered by r.finalizerName. + return r.updateFinalizersFiltered(ctx, resource) +} diff --git a/pkg/client/injection/reconciler/sources/v1beta1/apiserversource/stub/controller.go b/pkg/client/injection/reconciler/sources/v1beta1/apiserversource/stub/controller.go new file mode 100644 index 00000000000..530527250d9 --- /dev/null +++ b/pkg/client/injection/reconciler/sources/v1beta1/apiserversource/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 apiserversource + +import ( + context "context" + + apiserversource "knative.dev/eventing/pkg/client/injection/informers/sources/v1beta1/apiserversource" + v1beta1apiserversource "knative.dev/eventing/pkg/client/injection/reconciler/sources/v1beta1/apiserversource" + 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 ApiServerSource and returns the result of NewImpl. +func NewController( + ctx context.Context, + cmw configmap.Watcher, +) *controller.Impl { + logger := logging.FromContext(ctx) + + apiserversourceInformer := apiserversource.Get(ctx) + + // TODO: setup additional informers here. + + r := &Reconciler{} + impl := v1beta1apiserversource.NewImpl(ctx, r) + + logger.Info("Setting up event handlers.") + + apiserversourceInformer.Informer().AddEventHandler(controller.HandleAll(impl.Enqueue)) + + // TODO: add additional informer event handlers here. + + return impl +} diff --git a/pkg/client/injection/reconciler/sources/v1beta1/apiserversource/stub/reconciler.go b/pkg/client/injection/reconciler/sources/v1beta1/apiserversource/stub/reconciler.go new file mode 100644 index 00000000000..78aa620a8de --- /dev/null +++ b/pkg/client/injection/reconciler/sources/v1beta1/apiserversource/stub/reconciler.go @@ -0,0 +1,87 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package apiserversource + +import ( + context "context" + + v1 "k8s.io/api/core/v1" + v1beta1 "knative.dev/eventing/pkg/apis/sources/v1beta1" + apiserversource "knative.dev/eventing/pkg/client/injection/reconciler/sources/v1beta1/apiserversource" + 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 ApiServerSourceReconciled. +func newReconciledNormal(namespace, name string) reconciler.Event { + return reconciler.NewEvent(v1.EventTypeNormal, "ApiServerSourceReconciled", "ApiServerSource reconciled: \"%s/%s\"", namespace, name) +} + +// Reconciler implements controller.Reconciler for ApiServerSource resources. +type Reconciler struct { + // TODO: add additional requirements here. +} + +// Check that our Reconciler implements Interface +var _ apiserversource.Interface = (*Reconciler)(nil) + +// Optionally check that our Reconciler implements Finalizer +//var _ apiserversource.Finalizer = (*Reconciler)(nil) + +// Optionally check that our Reconciler implements ReadOnlyInterface +// Implement this to observe resources even when we are not the leader. +//var _ apiserversource.ReadOnlyInterface = (*Reconciler)(nil) + +// Optionally check that our Reconciler implements ReadOnlyFinalizer +// Implement this to observe tombstoned resources even when we are not +// the leader (best effort). +//var _ apiserversource.ReadOnlyFinalizer = (*Reconciler)(nil) + +// ReconcileKind implements Interface.ReconcileKind. +func (r *Reconciler) ReconcileKind(ctx context.Context, o *v1beta1.ApiServerSource) 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 *v1beta1.ApiServerSource) reconciler.Event { +// // TODO: add custom finalization logic here. +// return nil +//} + +// Optionally, use ObserveKind to observe the resource when we are not the leader. +// func (r *Reconciler) ObserveKind(ctx context.Context, o *v1beta1.ApiServerSource) reconciler.Event { +// // TODO: add custom observation logic here. +// return nil +// } + +// Optionally, use ObserveFinalizeKind to observe resources being finalized when we are no the leader. +//func (r *Reconciler) ObserveFinalizeKind(ctx context.Context, o *v1beta1.ApiServerSource) reconciler.Event { +// // TODO: add custom observation logic here. +// return nil +//} diff --git a/pkg/client/listers/sources/v1beta1/apiserversource.go b/pkg/client/listers/sources/v1beta1/apiserversource.go new file mode 100644 index 00000000000..1366b46db35 --- /dev/null +++ b/pkg/client/listers/sources/v1beta1/apiserversource.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 v1beta1 + +import ( + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" + v1beta1 "knative.dev/eventing/pkg/apis/sources/v1beta1" +) + +// ApiServerSourceLister helps list ApiServerSources. +type ApiServerSourceLister interface { + // List lists all ApiServerSources in the indexer. + List(selector labels.Selector) (ret []*v1beta1.ApiServerSource, err error) + // ApiServerSources returns an object that can list and get ApiServerSources. + ApiServerSources(namespace string) ApiServerSourceNamespaceLister + ApiServerSourceListerExpansion +} + +// apiServerSourceLister implements the ApiServerSourceLister interface. +type apiServerSourceLister struct { + indexer cache.Indexer +} + +// NewApiServerSourceLister returns a new ApiServerSourceLister. +func NewApiServerSourceLister(indexer cache.Indexer) ApiServerSourceLister { + return &apiServerSourceLister{indexer: indexer} +} + +// List lists all ApiServerSources in the indexer. +func (s *apiServerSourceLister) List(selector labels.Selector) (ret []*v1beta1.ApiServerSource, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1beta1.ApiServerSource)) + }) + return ret, err +} + +// ApiServerSources returns an object that can list and get ApiServerSources. +func (s *apiServerSourceLister) ApiServerSources(namespace string) ApiServerSourceNamespaceLister { + return apiServerSourceNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// ApiServerSourceNamespaceLister helps list and get ApiServerSources. +type ApiServerSourceNamespaceLister interface { + // List lists all ApiServerSources in the indexer for a given namespace. + List(selector labels.Selector) (ret []*v1beta1.ApiServerSource, err error) + // Get retrieves the ApiServerSource from the indexer for a given namespace and name. + Get(name string) (*v1beta1.ApiServerSource, error) + ApiServerSourceNamespaceListerExpansion +} + +// apiServerSourceNamespaceLister implements the ApiServerSourceNamespaceLister +// interface. +type apiServerSourceNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all ApiServerSources in the indexer for a given namespace. +func (s apiServerSourceNamespaceLister) List(selector labels.Selector) (ret []*v1beta1.ApiServerSource, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1beta1.ApiServerSource)) + }) + return ret, err +} + +// Get retrieves the ApiServerSource from the indexer for a given namespace and name. +func (s apiServerSourceNamespaceLister) Get(name string) (*v1beta1.ApiServerSource, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1beta1.Resource("apiserversource"), name) + } + return obj.(*v1beta1.ApiServerSource), nil +} diff --git a/pkg/client/listers/sources/v1beta1/expansion_generated.go b/pkg/client/listers/sources/v1beta1/expansion_generated.go index d1e6b925954..f36739de82b 100644 --- a/pkg/client/listers/sources/v1beta1/expansion_generated.go +++ b/pkg/client/listers/sources/v1beta1/expansion_generated.go @@ -18,6 +18,14 @@ limitations under the License. package v1beta1 +// ApiServerSourceListerExpansion allows custom methods to be added to +// ApiServerSourceLister. +type ApiServerSourceListerExpansion interface{} + +// ApiServerSourceNamespaceListerExpansion allows custom methods to be added to +// ApiServerSourceNamespaceLister. +type ApiServerSourceNamespaceListerExpansion interface{} + // ContainerSourceListerExpansion allows custom methods to be added to // ContainerSourceLister. type ContainerSourceListerExpansion interface{} From 3cef4813b67c5513b0d1ee89fab6bdf32423bf09 Mon Sep 17 00:00:00 2001 From: XiyueYu Date: Thu, 16 Jul 2020 13:52:27 -0700 Subject: [PATCH 2/8] fixed UT --- pkg/apis/sources/v1beta1/apiserver_lifecycle_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/apis/sources/v1beta1/apiserver_lifecycle_test.go b/pkg/apis/sources/v1beta1/apiserver_lifecycle_test.go index 8583e818ff7..0e434c316b6 100644 --- a/pkg/apis/sources/v1beta1/apiserver_lifecycle_test.go +++ b/pkg/apis/sources/v1beta1/apiserver_lifecycle_test.go @@ -40,7 +40,7 @@ func TestApiServerSourceGetGroupVersionKind(t *testing.T) { r := &ApiServerSource{} want := schema.GroupVersionKind{ Group: "sources.knative.dev", - Version: "v1alpha2", + Version: "v1beta1", Kind: "ApiServerSource", } if got := r.GetGroupVersionKind(); got != want { From 6da49671a1deba74934e86b4563049b9b6cb6bc0 Mon Sep 17 00:00:00 2001 From: XiyueYu Date: Thu, 16 Jul 2020 13:58:04 -0700 Subject: [PATCH 3/8] fixed v1alpha1 apiserver_lifecycle --- pkg/apis/sources/v1alpha1/apiserver_lifecycle.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/apis/sources/v1alpha1/apiserver_lifecycle.go b/pkg/apis/sources/v1alpha1/apiserver_lifecycle.go index a9dcf8c3239..fba140a7e9a 100644 --- a/pkg/apis/sources/v1alpha1/apiserver_lifecycle.go +++ b/pkg/apis/sources/v1alpha1/apiserver_lifecycle.go @@ -126,7 +126,7 @@ func (s *ApiServerSourceStatus) PropagateDeploymentAvailability(d *appsv1.Deploy } } if !deploymentAvailableFound { - PingSourceCondSet.Manage(s).MarkUnknown(PingSourceConditionDeployed, "DeploymentUnavailable", "The Deployment '%s' is unavailable.", d.Name) + apiserverCondSet.Manage(s).MarkUnknown(ApiServerConditionDeployed, "DeploymentUnavailable", "The Deployment '%s' is unavailable.", d.Name) } } From 3716f86dcb6caae1d080c505f05c37095408dc33 Mon Sep 17 00:00:00 2001 From: XiyueYu Date: Thu, 16 Jul 2020 15:53:01 -0700 Subject: [PATCH 4/8] added apiversource source conversion for v1beta1 --- cmd/webhook/main.go | 6 +- config/core/resources/apiserversource.yaml | 4 + .../sources/v1alpha1/apiserver_conversion.go | 9 +- .../v1alpha1/apiserver_conversion_test.go | 23 ++-- .../sources/v1alpha2/apiserver_conversion.go | 113 +++++++++++++++++- .../v1alpha2/apiserver_conversion_test.go | 20 +++- 6 files changed, 149 insertions(+), 26 deletions(-) diff --git a/cmd/webhook/main.go b/cmd/webhook/main.go index 8275835f2f8..6126de0a530 100644 --- a/cmd/webhook/main.go +++ b/cmd/webhook/main.go @@ -91,7 +91,8 @@ var ourTypes = map[schema.GroupVersionKind]resourcesemantics.GenericCRD{ sourcesv1alpha2.SchemeGroupVersion.WithKind("SinkBinding"): &sourcesv1alpha2.SinkBinding{}, sourcesv1alpha2.SchemeGroupVersion.WithKind("ContainerSource"): &sourcesv1alpha2.ContainerSource{}, // v1beta1 - sourcesv1beta1.SchemeGroupVersion.WithKind("SinkBinding"): &sourcesv1beta1.SinkBinding{}, + sourcesv1beta1.SchemeGroupVersion.WithKind("ApiServerSource"): &sourcesv1beta1.ApiServerSource{}, + sourcesv1beta1.SchemeGroupVersion.WithKind("SinkBinding"): &sourcesv1beta1.SinkBinding{}, // For group flows.knative.dev // v1beta1 @@ -309,12 +310,13 @@ func NewConversionController(ctx context.Context, cmw configmap.Watcher) *contro }, // Sources - sourcesv1alpha2.Kind("ApiServerSource"): { + sourcesv1beta1.Kind("ApiServerSource"): { DefinitionName: sources.ApiServerSourceResource.String(), HubVersion: sourcesv1alpha1_, Zygotes: map[string]conversion.ConvertibleObject{ sourcesv1alpha1_: &sourcesv1alpha1.ApiServerSource{}, sourcesv1alpha2_: &sourcesv1alpha2.ApiServerSource{}, + sourcesv1beta1_: &sourcesv1beta1.ApiServerSource{}, }, }, sourcesv1alpha2.Kind("PingSource"): { diff --git a/config/core/resources/apiserversource.yaml b/config/core/resources/apiserversource.yaml index 29661640eb5..65f0649a597 100644 --- a/config/core/resources/apiserversource.yaml +++ b/config/core/resources/apiserversource.yaml @@ -67,6 +67,10 @@ spec: name: v1alpha2 served: true storage: false + - <<: *version + name: v1beta1 + served: true + storage: false names: categories: - all diff --git a/pkg/apis/sources/v1alpha1/apiserver_conversion.go b/pkg/apis/sources/v1alpha1/apiserver_conversion.go index 970d25f3124..619ff14fce9 100644 --- a/pkg/apis/sources/v1alpha1/apiserver_conversion.go +++ b/pkg/apis/sources/v1alpha1/apiserver_conversion.go @@ -18,7 +18,6 @@ package v1alpha1 import ( "context" - "fmt" "reflect" "github.com/google/go-cmp/cmp" @@ -32,7 +31,7 @@ import ( ) // ConvertTo implements apis.Convertible. -// Converts source (from v1alpha1.ApiServerSource) into v1alpha2.ApiServerSource +// Converts source (from v1alpha1.ApiServerSource) into into a higher version. func (source *ApiServerSource) ConvertTo(ctx context.Context, obj apis.Convertible) error { switch sink := obj.(type) { case *v1alpha2.ApiServerSource: @@ -95,12 +94,12 @@ func (source *ApiServerSource) ConvertTo(ctx context.Context, obj apis.Convertib source.Status.SourceStatus.DeepCopyInto(&sink.Status.SourceStatus) return nil default: - return fmt.Errorf("Unknown conversion, got: %T", sink) + return apis.ConvertToViaProxy(ctx, source, &v1alpha2.ApiServerSource{}, sink) } } // ConvertFrom implements apis.Convertible. -// Converts obj from v1alpha2.ApiServerSource into v1alpha1.ApiServerSource +// Converts obj from a higher version into v1alpha1.ApiServerSource. func (sink *ApiServerSource) ConvertFrom(ctx context.Context, obj apis.Convertible) error { switch source := obj.(type) { case *v1alpha2.ApiServerSource: @@ -158,6 +157,6 @@ func (sink *ApiServerSource) ConvertFrom(ctx context.Context, obj apis.Convertib return nil default: - return fmt.Errorf("Unknown conversion, got: %T", source) + return apis.ConvertFromViaProxy(ctx, source, &v1alpha2.ApiServerSource{}, sink) } } diff --git a/pkg/apis/sources/v1alpha1/apiserver_conversion_test.go b/pkg/apis/sources/v1alpha1/apiserver_conversion_test.go index a0c536a5aa3..98ba9858697 100644 --- a/pkg/apis/sources/v1alpha1/apiserver_conversion_test.go +++ b/pkg/apis/sources/v1alpha1/apiserver_conversion_test.go @@ -25,6 +25,7 @@ import ( duckv1beta1 "knative.dev/pkg/apis/duck/v1beta1" "knative.dev/eventing/pkg/apis/sources/v1alpha2" + "knative.dev/eventing/pkg/apis/sources/v1beta1" "github.com/google/go-cmp/cmp" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -46,7 +47,7 @@ func TestApiServerSourceConversionBadType(t *testing.T) { func TestApiServerSourceConversionRoundTripUp(t *testing.T) { // Just one for now, just adding the for loop for ease of future changes. - versions := []apis.Convertible{&v1alpha2.ApiServerSource{}} + versions := []apis.Convertible{&v1alpha2.ApiServerSource{}, &v1beta1.ApiServerSource{}} path, _ := apis.ParseURL("/path") sink := duckv1beta1.Destination{ @@ -196,8 +197,6 @@ func TestApiServerSourceConversionRoundTripUp(t *testing.T) { // This tests round tripping from a higher version -> v1alpha1 and back to the higher version. func TestApiServerSourceConversionRoundTripDown(t *testing.T) { - // Just one for now, just adding the for loop for ease of future changes. - path, _ := apis.ParseURL("/path") sink := duckv1.Destination{ Ref: &duckv1.KReference{ @@ -221,28 +220,28 @@ func TestApiServerSourceConversionRoundTripDown(t *testing.T) { name string in apis.Convertible }{{name: "empty", - in: &v1alpha2.ApiServerSource{ + in: &v1beta1.ApiServerSource{ ObjectMeta: metav1.ObjectMeta{ Name: "apiserver-name", Namespace: "apiserver-ns", Generation: 17, }, - Spec: v1alpha2.ApiServerSourceSpec{}, - Status: v1alpha2.ApiServerSourceStatus{}, + Spec: v1beta1.ApiServerSourceSpec{}, + Status: v1beta1.ApiServerSourceStatus{}, }, }, {name: "simple configuration", - in: &v1alpha2.ApiServerSource{ + in: &v1beta1.ApiServerSource{ ObjectMeta: metav1.ObjectMeta{ Name: "apiserver-name", Namespace: "apiserver-ns", Generation: 17, }, - Spec: v1alpha2.ApiServerSourceSpec{ + Spec: v1beta1.ApiServerSourceSpec{ SourceSpec: duckv1.SourceSpec{ Sink: sink, }, }, - Status: v1alpha2.ApiServerSourceStatus{ + Status: v1beta1.ApiServerSourceStatus{ SourceStatus: duckv1.SourceStatus{ Status: duckv1.Status{ ObservedGeneration: 1, @@ -256,19 +255,19 @@ func TestApiServerSourceConversionRoundTripDown(t *testing.T) { }, }, }, {name: "full", - in: &v1alpha2.ApiServerSource{ + in: &v1beta1.ApiServerSource{ ObjectMeta: metav1.ObjectMeta{ Name: "apiserver-name", Namespace: "apiserver-ns", Generation: 17, }, - Spec: v1alpha2.ApiServerSourceSpec{ + Spec: v1beta1.ApiServerSourceSpec{ SourceSpec: duckv1.SourceSpec{ Sink: sink, CloudEventOverrides: &ceOverrides, }, }, - Status: v1alpha2.ApiServerSourceStatus{ + Status: v1beta1.ApiServerSourceStatus{ SourceStatus: duckv1.SourceStatus{ Status: duckv1.Status{ ObservedGeneration: 1, diff --git a/pkg/apis/sources/v1alpha2/apiserver_conversion.go b/pkg/apis/sources/v1alpha2/apiserver_conversion.go index 40709ae2c28..89660e600c0 100644 --- a/pkg/apis/sources/v1alpha2/apiserver_conversion.go +++ b/pkg/apis/sources/v1alpha2/apiserver_conversion.go @@ -18,17 +18,120 @@ package v1alpha2 import ( "context" - "fmt" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "knative.dev/eventing/pkg/apis/sources/v1beta1" "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" ) // ConvertTo implements apis.Convertible -func (source *ApiServerSource) ConvertTo(ctx context.Context, sink apis.Convertible) error { - return fmt.Errorf("v1alpha2 is the highest known version, got: %T", sink) +// Converts source (from v1alpha2.ApiServerSource) into into a higher version. +func (source *ApiServerSource) ConvertTo(ctx context.Context, obj apis.Convertible) error { + switch sink := obj.(type) { + case *v1beta1.ApiServerSource: + // Meta + sink.ObjectMeta = source.ObjectMeta + + // Spec + + if len(source.Spec.Resources) > 0 { + sink.Spec.Resources = make([]v1beta1.APIVersionKindSelector, len(source.Spec.Resources)) + } + for i, v := range source.Spec.Resources { + sink.Spec.Resources[i] = v1beta1.APIVersionKindSelector{ + APIVersion: v.APIVersion, + Kind: v.Kind, + } + + if v.LabelSelector != nil { + sink.Spec.Resources[i].LabelSelector = &metav1.LabelSelector{} + v.LabelSelector.DeepCopyInto(sink.Spec.Resources[i].LabelSelector) + } + } + + sink.Spec.EventMode = source.Spec.EventMode + + // Optional Spec + + if source.Spec.ResourceOwner != nil { + sink.Spec.ResourceOwner = &v1beta1.APIVersionKind{ + Kind: source.Spec.ResourceOwner.Kind, + APIVersion: source.Spec.ResourceOwner.APIVersion, + } + } + + var ref *duckv1.KReference + if source.Spec.Sink.Ref != nil { + ref = &duckv1.KReference{ + Kind: source.Spec.Sink.Ref.Kind, + Namespace: source.Spec.Sink.Ref.Namespace, + Name: source.Spec.Sink.Ref.Name, + APIVersion: source.Spec.Sink.Ref.APIVersion, + } + } + sink.Spec.Sink = duckv1.Destination{ + Ref: ref, + URI: source.Spec.Sink.URI, + } + + if source.Spec.CloudEventOverrides != nil { + sink.Spec.CloudEventOverrides = source.Spec.CloudEventOverrides.DeepCopy() + } + + sink.Spec.ServiceAccountName = source.Spec.ServiceAccountName + + // Status + source.Status.SourceStatus.DeepCopyInto(&sink.Status.SourceStatus) + return nil + default: + return apis.ConvertToViaProxy(ctx, source, &v1beta1.ApiServerSource{}, sink) + } } // ConvertFrom implements apis.Convertible -func (sink *ApiServerSource) ConvertFrom(ctx context.Context, source apis.Convertible) error { - return fmt.Errorf("v1alpha2 is the highest known version, got: %T", source) +// Converts obj from a higher version into v1alpha2.ApiServerSource. +func (sink *ApiServerSource) ConvertFrom(ctx context.Context, obj apis.Convertible) error { + switch source := obj.(type) { + case *v1beta1.ApiServerSource: + // Meta + sink.ObjectMeta = source.ObjectMeta + + // Spec + sink.Spec.EventMode = source.Spec.EventMode + + sink.Spec.CloudEventOverrides = source.Spec.CloudEventOverrides + + sink.Spec.Sink = source.Spec.Sink + + if len(source.Spec.Resources) > 0 { + sink.Spec.Resources = make([]APIVersionKindSelector, len(source.Spec.Resources)) + } + for i, v := range source.Spec.Resources { + sink.Spec.Resources[i] = APIVersionKindSelector{} + sink.Spec.Resources[i].APIVersion = v.APIVersion + sink.Spec.Resources[i].Kind = v.Kind + if v.LabelSelector != nil { + sink.Spec.Resources[i].LabelSelector = v.LabelSelector.DeepCopy() + } + } + + // Spec Optionals + + if source.Spec.ResourceOwner != nil { + sink.Spec.ResourceOwner = &APIVersionKind{ + Kind: source.Spec.ResourceOwner.Kind, + APIVersion: source.Spec.ResourceOwner.APIVersion, + } + } + + sink.Spec.ServiceAccountName = source.Spec.ServiceAccountName + + // Status + source.Status.SourceStatus.DeepCopyInto(&sink.Status.SourceStatus) + + return nil + default: + return apis.ConvertFromViaProxy(ctx, source, &v1beta1.ApiServerSource{}, sink) + } } diff --git a/pkg/apis/sources/v1alpha2/apiserver_conversion_test.go b/pkg/apis/sources/v1alpha2/apiserver_conversion_test.go index 62bd3b96b85..f9f1f3fcd09 100644 --- a/pkg/apis/sources/v1alpha2/apiserver_conversion_test.go +++ b/pkg/apis/sources/v1alpha2/apiserver_conversion_test.go @@ -14,6 +14,22 @@ See the License for the specific language governing permissions and limitations under the License. */ +/* +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 ( @@ -21,8 +37,8 @@ import ( "testing" ) -func TestApiServerConversionBadType(t *testing.T) { - good, bad := &ApiServerSource{}, &ApiServerSource{} +func TestApiServerSourceConversionBadType(t *testing.T) { + good, bad := &ApiServerSource{}, &dummy{} if err := good.ConvertTo(context.Background(), bad); err == nil { t.Errorf("ConvertTo() = %#v, wanted error", bad) From 6c35aae25910040b605ca960f7e415c9bb017f5a Mon Sep 17 00:00:00 2001 From: XiyueYu Date: Thu, 16 Jul 2020 19:47:38 -0700 Subject: [PATCH 5/8] fixed format --- config/core/resources/apiserversource.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/config/core/resources/apiserversource.yaml b/config/core/resources/apiserversource.yaml index 65f0649a597..f9ad1d94eab 100644 --- a/config/core/resources/apiserversource.yaml +++ b/config/core/resources/apiserversource.yaml @@ -73,10 +73,10 @@ spec: storage: false names: categories: - - all - - knative - - eventing - - sources + - all + - knative + - eventing + - sources kind: ApiServerSource plural: apiserversources scope: Namespaced From de3dce6a57f129dd66550c375cf84cb11c4c9645 Mon Sep 17 00:00:00 2001 From: XiyueYu Date: Thu, 16 Jul 2020 20:21:50 -0700 Subject: [PATCH 6/8] added ut for v1alpha2 conversion --- .../v1alpha2/apiserver_conversion_test.go | 315 +++++++++++++++++- 1 file changed, 299 insertions(+), 16 deletions(-) diff --git a/pkg/apis/sources/v1alpha2/apiserver_conversion_test.go b/pkg/apis/sources/v1alpha2/apiserver_conversion_test.go index f9f1f3fcd09..c8137e0cd91 100644 --- a/pkg/apis/sources/v1alpha2/apiserver_conversion_test.go +++ b/pkg/apis/sources/v1alpha2/apiserver_conversion_test.go @@ -14,27 +14,19 @@ See the License for the specific language governing permissions and limitations under the License. */ -/* -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" + "reflect" "testing" + + "knative.dev/eventing/pkg/apis/sources/v1beta1" + + "github.com/google/go-cmp/cmp" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" ) func TestApiServerSourceConversionBadType(t *testing.T) { @@ -48,3 +40,294 @@ func TestApiServerSourceConversionBadType(t *testing.T) { t.Errorf("ConvertFrom() = %#v, wanted error", good) } } + +func TestApiServerSourceConversionRoundTripUp(t *testing.T) { + // Just one for now, just adding the for loop for ease of future changes. + versions := []apis.Convertible{&v1beta1.ApiServerSource{}} + + path, _ := apis.ParseURL("/path") + sink := duckv1.Destination{ + Ref: &duckv1.KReference{ + Kind: "Foo", + Namespace: "Bar", + Name: "Baz", + APIVersion: "Baf", + }, + URI: path, + } + sinkUri, _ := apis.ParseURL("http://example.com/path") + + tests := []struct { + name string + in *ApiServerSource + }{{name: "empty", + in: &ApiServerSource{ + ObjectMeta: metav1.ObjectMeta{ + Name: "apiserver-name", + Namespace: "apiserver-ns", + Generation: 17, + }, + Spec: ApiServerSourceSpec{}, + Status: ApiServerSourceStatus{ + SourceStatus: duckv1.SourceStatus{ + Status: duckv1.Status{ + ObservedGeneration: 1, + Conditions: duckv1.Conditions{{ + Type: "Ready", + Status: "True", + }}, + }, + }, + }, + }, + }, {name: "simple configuration", + in: &ApiServerSource{ + ObjectMeta: metav1.ObjectMeta{ + Name: "apiserver-name", + Namespace: "apiserver-ns", + Generation: 17, + }, + Spec: ApiServerSourceSpec{ + SourceSpec: duckv1.SourceSpec{ + Sink: sink, + }, + Resources: []APIVersionKindSelector{{ + APIVersion: "A1", + Kind: "K1", + LabelSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"A1": "K1"}, + }, + }, { + APIVersion: "A2", + Kind: "K2", + }}, + EventMode: "Ref", + }, + Status: ApiServerSourceStatus{ + SourceStatus: duckv1.SourceStatus{ + Status: duckv1.Status{ + ObservedGeneration: 1, + Conditions: duckv1.Conditions{{ + Type: "Ready", + Status: "Unknown", + }}, + }, + SinkURI: sinkUri, + }, + }, + }, + }, {name: "full", + in: &ApiServerSource{ + ObjectMeta: metav1.ObjectMeta{ + Name: "apiserver-name", + Namespace: "apiserver-ns", + Generation: 17, + }, + Spec: ApiServerSourceSpec{ + SourceSpec: duckv1.SourceSpec{ + Sink: sink, + CloudEventOverrides: &duckv1.CloudEventOverrides{ + Extensions: map[string]string{ + "foo": "bar", + "baz": "baf", + }, + }, + }, + Resources: []APIVersionKindSelector{{ + APIVersion: "A1", + Kind: "K1", + LabelSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "foo": "bar", + }, + MatchExpressions: []metav1.LabelSelectorRequirement{{ + Key: "aKey", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"the", "house"}, + }}, + }, + }, { + APIVersion: "A2", + Kind: "K2", + }}, + ResourceOwner: &APIVersionKind{ + APIVersion: "custom/v1", + Kind: "Parent", + }, + EventMode: "Resource", + ServiceAccountName: "adult", + }, + Status: ApiServerSourceStatus{ + SourceStatus: duckv1.SourceStatus{ + Status: duckv1.Status{ + ObservedGeneration: 1, + Conditions: duckv1.Conditions{{ + Type: "Ready", + Status: "True", + }}, + }, + SinkURI: sinkUri, + }, + }, + }, + }} + for _, test := range tests { + for _, version := range versions { + t.Run(test.name, func(t *testing.T) { + ver := version + if err := test.in.ConvertTo(context.Background(), ver); err != nil { + t.Errorf("ConvertTo() = %v", err) + } + + got := &ApiServerSource{} + + if err := got.ConvertFrom(context.Background(), ver); err != nil { + t.Errorf("ConvertFrom() = %v", err) + } + if diff := cmp.Diff(test.in, got); diff != "" { + t.Errorf("roundtrip (-want, +got) = %v", diff) + } + }) + } + } +} + +// This tests round tripping from a higher version -> v1alpha1 and back to the higher version. +func TestApiServerSourceConversionRoundTripDown(t *testing.T) { + path, _ := apis.ParseURL("/path") + sink := duckv1.Destination{ + Ref: &duckv1.KReference{ + Kind: "Foo", + Namespace: "Bar", + Name: "Baz", + APIVersion: "Baf", + }, + URI: path, + } + sinkURI, _ := apis.ParseURL("http://example.com/path") + + ceOverrides := duckv1.CloudEventOverrides{ + Extensions: map[string]string{ + "foo": "bar", + "baz": "baf", + }, + } + + tests := []struct { + name string + in apis.Convertible + }{{name: "empty", + in: &v1beta1.ApiServerSource{ + ObjectMeta: metav1.ObjectMeta{ + Name: "apiserver-name", + Namespace: "apiserver-ns", + Generation: 17, + }, + Spec: v1beta1.ApiServerSourceSpec{}, + Status: v1beta1.ApiServerSourceStatus{}, + }, + }, {name: "simple configuration", + in: &v1beta1.ApiServerSource{ + ObjectMeta: metav1.ObjectMeta{ + Name: "apiserver-name", + Namespace: "apiserver-ns", + Generation: 17, + }, + Spec: v1beta1.ApiServerSourceSpec{ + SourceSpec: duckv1.SourceSpec{ + Sink: sink, + }, + Resources: []v1beta1.APIVersionKindSelector{{ + APIVersion: "A1", + Kind: "K1", + LabelSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"A1": "K1"}, + }, + }, { + APIVersion: "A2", + Kind: "K2", + }}, + EventMode: "Ref", + }, + Status: v1beta1.ApiServerSourceStatus{ + SourceStatus: duckv1.SourceStatus{ + Status: duckv1.Status{ + ObservedGeneration: 1, + Conditions: duckv1.Conditions{{ + Type: "Ready", + Status: "True", + }}, + }, + SinkURI: sinkURI, + }, + }, + }, + }, {name: "full", + in: &v1beta1.ApiServerSource{ + ObjectMeta: metav1.ObjectMeta{ + Name: "apiserver-name", + Namespace: "apiserver-ns", + Generation: 17, + }, + Spec: v1beta1.ApiServerSourceSpec{ + SourceSpec: duckv1.SourceSpec{ + Sink: sink, + CloudEventOverrides: &ceOverrides, + }, + Resources: []v1beta1.APIVersionKindSelector{{ + APIVersion: "A1", + Kind: "K1", + LabelSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "foo": "bar", + }, + MatchExpressions: []metav1.LabelSelectorRequirement{{ + Key: "aKey", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"the", "house"}, + }}, + }, + }, { + APIVersion: "A2", + Kind: "K2", + }}, + ResourceOwner: &v1beta1.APIVersionKind{ + APIVersion: "custom/v1", + Kind: "Parent", + }, + EventMode: "Resource", + ServiceAccountName: "adult", + }, + Status: v1beta1.ApiServerSourceStatus{ + SourceStatus: duckv1.SourceStatus{ + Status: duckv1.Status{ + ObservedGeneration: 1, + Conditions: duckv1.Conditions{{ + Type: "Ready", + Status: "True", + }}, + }, + SinkURI: sinkURI, + }, + }, + }, + }} + for _, test := range tests { + + t.Run(test.name, func(t *testing.T) { + down := &ApiServerSource{} + if err := down.ConvertFrom(context.Background(), test.in); err != nil { + t.Errorf("ConvertTo() = %v", err) + } + + got := (reflect.New(reflect.TypeOf(test.in).Elem()).Interface()).(apis.Convertible) + + if err := down.ConvertTo(context.Background(), got); err != nil { + t.Errorf("ConvertFrom() = %v", err) + } + if diff := cmp.Diff(test.in, got); diff != "" { + t.Errorf("roundtrip (-want, +got) = %v", diff) + } + }) + } +} From dd6a551ec124f72753eeedc099e868fb86507bcb Mon Sep 17 00:00:00 2001 From: XiyueYu Date: Fri, 17 Jul 2020 12:33:58 -0700 Subject: [PATCH 7/8] reconciler and e2e for v1beta1 apiserversource --- pkg/adapter/apiserver/config.go | 4 +- pkg/adapter/apiserver/delegate_test.go | 14 +- pkg/adapter/apiserver/events/events.go | 14 +- pkg/adapter/apiserver/filter_test.go | 26 +- pkg/adapter/apiserver/ref_test.go | 14 +- .../apiserversource/apiserversource.go | 16 +- .../apiserversource/apiserversource_test.go | 294 +++++++++--------- pkg/reconciler/apiserversource/controller.go | 4 +- .../apiserversource/controller_test.go | 2 +- .../resources/receive_adapter.go | 4 +- .../resources/receive_adapter_test.go | 14 +- pkg/reconciler/testing/apiserversource.go | 76 +++-- pkg/reconciler/testing/v1beta1/listers.go | 6 + ....go => source_api_server_v1alpha2_test.go} | 14 +- test/e2e/source_api_server_v1beta1_test.go | 257 +++++++++++++++ test/lib/creation.go | 15 +- 16 files changed, 537 insertions(+), 237 deletions(-) rename test/e2e/{source_api_server_test.go => source_api_server_v1alpha2_test.go} (95%) create mode 100644 test/e2e/source_api_server_v1beta1_test.go diff --git a/pkg/adapter/apiserver/config.go b/pkg/adapter/apiserver/config.go index 9f65d6ea5eb..d4174e7db1c 100644 --- a/pkg/adapter/apiserver/config.go +++ b/pkg/adapter/apiserver/config.go @@ -17,7 +17,7 @@ package apiserver import ( "k8s.io/apimachinery/pkg/runtime/schema" - "knative.dev/eventing/pkg/apis/sources/v1alpha2" + "knative.dev/eventing/pkg/apis/sources/v1beta1" ) type ResourceWatch struct { @@ -44,7 +44,7 @@ type Config struct { // owned by a specific resource type. If ResourceOwner matches Resources[n] // then Resources[n] is allowed to pass the ResourceOwner filter. // +optional - ResourceOwner *v1alpha2.APIVersionKind `json:"owner,omitempty"` + ResourceOwner *v1beta1.APIVersionKind `json:"owner,omitempty"` // EventMode controls the format of the event. // `Reference` sends a dataref event type for the resource under watch. diff --git a/pkg/adapter/apiserver/delegate_test.go b/pkg/adapter/apiserver/delegate_test.go index f01c7dc8230..38100764291 100644 --- a/pkg/adapter/apiserver/delegate_test.go +++ b/pkg/adapter/apiserver/delegate_test.go @@ -18,43 +18,43 @@ package apiserver import ( "testing" - sourcesv1alpha1 "knative.dev/eventing/pkg/apis/sources/v1alpha1" + sourcesv1beta1 "knative.dev/eventing/pkg/apis/sources/v1beta1" ) func TestResourceAddEvent(t *testing.T) { d, ce := makeResourceAndTestingClient() d.Add(simplePod("unit", "test")) - validateSent(t, ce, sourcesv1alpha1.ApiServerSourceAddEventType) + validateSent(t, ce, sourcesv1beta1.ApiServerSourceAddEventType) } func TestResourceUpdateEvent(t *testing.T) { d, ce := makeResourceAndTestingClient() d.Update(simplePod("unit", "test")) - validateSent(t, ce, sourcesv1alpha1.ApiServerSourceUpdateEventType) + validateSent(t, ce, sourcesv1beta1.ApiServerSourceUpdateEventType) } func TestResourceDeleteEvent(t *testing.T) { d, ce := makeResourceAndTestingClient() d.Delete(simplePod("unit", "test")) - validateSent(t, ce, sourcesv1alpha1.ApiServerSourceDeleteEventType) + validateSent(t, ce, sourcesv1beta1.ApiServerSourceDeleteEventType) } func TestResourceAddEventNil(t *testing.T) { d, ce := makeResourceAndTestingClient() d.Add(nil) - validateNotSent(t, ce, sourcesv1alpha1.ApiServerSourceAddEventType) + validateNotSent(t, ce, sourcesv1beta1.ApiServerSourceAddEventType) } func TestResourceUpdateEventNil(t *testing.T) { d, ce := makeResourceAndTestingClient() d.Update(nil) - validateNotSent(t, ce, sourcesv1alpha1.ApiServerSourceUpdateEventType) + validateNotSent(t, ce, sourcesv1beta1.ApiServerSourceUpdateEventType) } func TestResourceDeleteEventNil(t *testing.T) { d, ce := makeResourceAndTestingClient() d.Delete(nil) - validateNotSent(t, ce, sourcesv1alpha1.ApiServerSourceDeleteEventType) + validateNotSent(t, ce, sourcesv1beta1.ApiServerSourceDeleteEventType) } // HACKHACKHACK For test coverage. diff --git a/pkg/adapter/apiserver/events/events.go b/pkg/adapter/apiserver/events/events.go index b5fd810ce30..0aa6c55ee68 100644 --- a/pkg/adapter/apiserver/events/events.go +++ b/pkg/adapter/apiserver/events/events.go @@ -24,7 +24,7 @@ import ( corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - sourcesv1alpha2 "knative.dev/eventing/pkg/apis/sources/v1alpha2" + sourcesv1beta1 "knative.dev/eventing/pkg/apis/sources/v1beta1" ) func MakeAddEvent(source string, obj interface{}, ref bool) (cloudevents.Event, error) { @@ -37,10 +37,10 @@ func MakeAddEvent(source string, obj interface{}, ref bool) (cloudevents.Event, var eventType string if ref { data = getRef(object) - eventType = sourcesv1alpha2.ApiServerSourceAddRefEventType + eventType = sourcesv1beta1.ApiServerSourceAddRefEventType } else { data = object - eventType = sourcesv1alpha2.ApiServerSourceAddEventType + eventType = sourcesv1beta1.ApiServerSourceAddEventType } return makeEvent(source, eventType, object, data) @@ -56,10 +56,10 @@ func MakeUpdateEvent(source string, obj interface{}, ref bool) (cloudevents.Even var eventType string if ref { data = getRef(object) - eventType = sourcesv1alpha2.ApiServerSourceUpdateRefEventType + eventType = sourcesv1beta1.ApiServerSourceUpdateRefEventType } else { data = object - eventType = sourcesv1alpha2.ApiServerSourceUpdateEventType + eventType = sourcesv1beta1.ApiServerSourceUpdateEventType } return makeEvent(source, eventType, object, data) @@ -74,10 +74,10 @@ func MakeDeleteEvent(source string, obj interface{}, ref bool) (cloudevents.Even var eventType string if ref { data = getRef(object) - eventType = sourcesv1alpha2.ApiServerSourceDeleteRefEventType + eventType = sourcesv1beta1.ApiServerSourceDeleteRefEventType } else { data = object - eventType = sourcesv1alpha2.ApiServerSourceDeleteEventType + eventType = sourcesv1beta1.ApiServerSourceDeleteEventType } return makeEvent(source, eventType, object, data) diff --git a/pkg/adapter/apiserver/filter_test.go b/pkg/adapter/apiserver/filter_test.go index cb43c3bd00e..790f295cc72 100644 --- a/pkg/adapter/apiserver/filter_test.go +++ b/pkg/adapter/apiserver/filter_test.go @@ -20,79 +20,79 @@ import ( "testing" adaptertest "knative.dev/eventing/pkg/adapter/v2/test" - sourcesv1alpha1 "knative.dev/eventing/pkg/apis/sources/v1alpha1" + sourcesv1beta1 "knative.dev/eventing/pkg/apis/sources/v1beta1" ) func TestControllerAddEventWithNoController(t *testing.T) { c, tc := makeController("v1", "Pod") c.Add(simplePod("unit", "test")) - validateNotSent(t, tc, sourcesv1alpha1.ApiServerSourceAddRefEventType) + validateNotSent(t, tc, sourcesv1beta1.ApiServerSourceAddRefEventType) } func TestControllerAddEventWithWrongController(t *testing.T) { c, tc := makeController("v1", "Pod") c.Add(simpleOwnedPod("unit", "test")) - validateNotSent(t, tc, sourcesv1alpha1.ApiServerSourceAddRefEventType) + validateNotSent(t, tc, sourcesv1beta1.ApiServerSourceAddRefEventType) } func TestControllerAddEventWithGoodController(t *testing.T) { c, tc := makeController("apps/v1", "ReplicaSet") c.Add(simpleOwnedPod("unit", "test")) - validateSent(t, tc, sourcesv1alpha1.ApiServerSourceAddRefEventType) + validateSent(t, tc, sourcesv1beta1.ApiServerSourceAddRefEventType) } func TestControllerAddEventWithGoodControllerNoAPIVersion(t *testing.T) { c, tc := makeController("", "ReplicaSet") c.Add(simpleOwnedPod("unit", "test")) - validateSent(t, tc, sourcesv1alpha1.ApiServerSourceAddRefEventType) + validateSent(t, tc, sourcesv1beta1.ApiServerSourceAddRefEventType) } func TestControllerUpdateEventWithNoController(t *testing.T) { c, tc := makeController("v1", "Pod") c.Update(simplePod("unit", "test")) - validateNotSent(t, tc, sourcesv1alpha1.ApiServerSourceUpdateRefEventType) + validateNotSent(t, tc, sourcesv1beta1.ApiServerSourceUpdateRefEventType) } func TestControllerUpdateEventWithWrongController(t *testing.T) { c, tc := makeController("v1", "Pod") c.Update(simpleOwnedPod("unit", "test")) - validateNotSent(t, tc, sourcesv1alpha1.ApiServerSourceUpdateRefEventType) + validateNotSent(t, tc, sourcesv1beta1.ApiServerSourceUpdateRefEventType) } func TestControllerUpdateEventWithGoodController(t *testing.T) { c, tc := makeController("apps/v1", "ReplicaSet") c.Update(simpleOwnedPod("unit", "test")) - validateSent(t, tc, sourcesv1alpha1.ApiServerSourceUpdateRefEventType) + validateSent(t, tc, sourcesv1beta1.ApiServerSourceUpdateRefEventType) } func TestControllerUpdateEventWithGoodControllerNoAPIVersion(t *testing.T) { c, tc := makeController("", "ReplicaSet") c.Update(simpleOwnedPod("unit", "test")) - validateSent(t, tc, sourcesv1alpha1.ApiServerSourceUpdateRefEventType) + validateSent(t, tc, sourcesv1beta1.ApiServerSourceUpdateRefEventType) } func TestControllerDeleteEventWithNoController(t *testing.T) { c, tc := makeController("v1", "Pod") c.Delete(simplePod("unit", "test")) - validateNotSent(t, tc, sourcesv1alpha1.ApiServerSourceDeleteRefEventType) + validateNotSent(t, tc, sourcesv1beta1.ApiServerSourceDeleteRefEventType) } func TestControllerDeleteEventWithWrongController(t *testing.T) { c, tc := makeController("v1", "Pod") c.Delete(simpleOwnedPod("unit", "test")) - validateNotSent(t, tc, sourcesv1alpha1.ApiServerSourceDeleteRefEventType) + validateNotSent(t, tc, sourcesv1beta1.ApiServerSourceDeleteRefEventType) } func TestControllerDeleteEventWithGoodController(t *testing.T) { c, tc := makeController("apps/v1", "ReplicaSet") c.Delete(simpleOwnedPod("unit", "test")) - validateSent(t, tc, sourcesv1alpha1.ApiServerSourceDeleteRefEventType) + validateSent(t, tc, sourcesv1beta1.ApiServerSourceDeleteRefEventType) } func TestControllerDeleteEventWithGoodControllerNoAPIVersion(t *testing.T) { c, tc := makeController("", "ReplicaSet") c.Delete(simpleOwnedPod("unit", "test")) - validateSent(t, tc, sourcesv1alpha1.ApiServerSourceDeleteRefEventType) + validateSent(t, tc, sourcesv1beta1.ApiServerSourceDeleteRefEventType) } func makeController(apiVersion, kind string) (*controllerFilter, *adaptertest.TestCloudEventsClient) { diff --git a/pkg/adapter/apiserver/ref_test.go b/pkg/adapter/apiserver/ref_test.go index 30ecfc8b3f1..cf4f21d1153 100644 --- a/pkg/adapter/apiserver/ref_test.go +++ b/pkg/adapter/apiserver/ref_test.go @@ -18,44 +18,44 @@ package apiserver import ( "testing" - sourcesv1alpha1 "knative.dev/eventing/pkg/apis/sources/v1alpha1" + sourcesv1beta1 "knative.dev/eventing/pkg/apis/sources/v1beta1" ) func TestRefAddEvent(t *testing.T) { d, ce := makeRefAndTestingClient() d.Add(simplePod("unit", "test")) - validateSent(t, ce, sourcesv1alpha1.ApiServerSourceAddRefEventType) + validateSent(t, ce, sourcesv1beta1.ApiServerSourceAddRefEventType) } func TestRefUpdateEvent(t *testing.T) { d, ce := makeRefAndTestingClient() d.Update(simplePod("unit", "test")) - validateSent(t, ce, sourcesv1alpha1.ApiServerSourceUpdateRefEventType) + validateSent(t, ce, sourcesv1beta1.ApiServerSourceUpdateRefEventType) } func TestRefDeleteEvent(t *testing.T) { d, ce := makeRefAndTestingClient() d.Delete(simplePod("unit", "test")) - validateSent(t, ce, sourcesv1alpha1.ApiServerSourceDeleteRefEventType) + validateSent(t, ce, sourcesv1beta1.ApiServerSourceDeleteRefEventType) } func TestRefAddEventNil(t *testing.T) { d, ce := makeRefAndTestingClient() d.Add(nil) - validateNotSent(t, ce, sourcesv1alpha1.ApiServerSourceAddRefEventType) + validateNotSent(t, ce, sourcesv1beta1.ApiServerSourceAddRefEventType) } func TestRefUpdateEventNil(t *testing.T) { d, ce := makeRefAndTestingClient() d.Update(nil) - validateNotSent(t, ce, sourcesv1alpha1.ApiServerSourceUpdateRefEventType) + validateNotSent(t, ce, sourcesv1beta1.ApiServerSourceUpdateRefEventType) } func TestRefDeleteEventNil(t *testing.T) { d, ce := makeRefAndTestingClient() d.Delete(nil) - validateNotSent(t, ce, sourcesv1alpha1.ApiServerSourceDeleteRefEventType) + validateNotSent(t, ce, sourcesv1beta1.ApiServerSourceDeleteRefEventType) } // HACKHACKHACK For test coverage. diff --git a/pkg/reconciler/apiserversource/apiserversource.go b/pkg/reconciler/apiserversource/apiserversource.go index 68c8db52e5d..2b7067960d7 100644 --- a/pkg/reconciler/apiserversource/apiserversource.go +++ b/pkg/reconciler/apiserversource/apiserversource.go @@ -37,9 +37,9 @@ import ( pkgreconciler "knative.dev/pkg/reconciler" "knative.dev/pkg/resolver" - "knative.dev/eventing/pkg/apis/sources/v1alpha2" - apiserversourcereconciler "knative.dev/eventing/pkg/client/injection/reconciler/sources/v1alpha2/apiserversource" - listers "knative.dev/eventing/pkg/client/listers/sources/v1alpha2" + "knative.dev/eventing/pkg/apis/sources/v1beta1" + apiserversourcereconciler "knative.dev/eventing/pkg/client/injection/reconciler/sources/v1beta1/apiserversource" + listers "knative.dev/eventing/pkg/client/listers/sources/v1beta1" "knative.dev/eventing/pkg/logging" "knative.dev/eventing/pkg/reconciler/apiserversource/resources" reconcilersource "knative.dev/eventing/pkg/reconciler/source" @@ -84,7 +84,7 @@ type Reconciler struct { var _ apiserversourcereconciler.Interface = (*Reconciler)(nil) -func (r *Reconciler) ReconcileKind(ctx context.Context, source *v1alpha2.ApiServerSource) pkgreconciler.Event { +func (r *Reconciler) ReconcileKind(ctx context.Context, source *v1beta1.ApiServerSource) pkgreconciler.Event { // This Source attempts to reconcile three things. // 1. Determine the sink's URI. // - Nothing to delete. @@ -128,7 +128,7 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, source *v1alpha2.ApiServ return newReconciledNormal(source.Namespace, source.Name) } -func (r *Reconciler) createReceiveAdapter(ctx context.Context, src *v1alpha2.ApiServerSource, sinkURI string) (*appsv1.Deployment, error) { +func (r *Reconciler) createReceiveAdapter(ctx context.Context, src *v1beta1.ApiServerSource, sinkURI string) (*appsv1.Deployment, error) { // TODO: missing. // if err := checkResourcesStatus(src); err != nil { // return nil, err @@ -196,7 +196,7 @@ func (r *Reconciler) podSpecChanged(oldPodSpec corev1.PodSpec, newPodSpec corev1 return false } -func (r *Reconciler) runAccessCheck(src *v1alpha2.ApiServerSource) error { +func (r *Reconciler) runAccessCheck(src *v1beta1.ApiServerSource) error { if src.Spec.Resources == nil || len(src.Spec.Resources) == 0 { src.Status.MarkSufficientPermissions() return nil @@ -263,8 +263,8 @@ func (r *Reconciler) runAccessCheck(src *v1alpha2.ApiServerSource) error { } func (r *Reconciler) createCloudEventAttributes() []duckv1.CloudEventAttributes { - ceAttributes := make([]duckv1.CloudEventAttributes, 0, len(v1alpha2.ApiServerSourceEventTypes)) - for _, apiServerSourceType := range v1alpha2.ApiServerSourceEventTypes { + ceAttributes := make([]duckv1.CloudEventAttributes, 0, len(v1beta1.ApiServerSourceEventTypes)) + for _, apiServerSourceType := range v1beta1.ApiServerSourceEventTypes { ceAttributes = append(ceAttributes, duckv1.CloudEventAttributes{ Type: apiServerSourceType, Source: r.ceSource, diff --git a/pkg/reconciler/apiserversource/apiserversource_test.go b/pkg/reconciler/apiserversource/apiserversource_test.go index 86a610726f4..bb2a45a31dc 100644 --- a/pkg/reconciler/apiserversource/apiserversource_test.go +++ b/pkg/reconciler/apiserversource/apiserversource_test.go @@ -30,9 +30,9 @@ import ( "k8s.io/client-go/kubernetes/scheme" clientgotesting "k8s.io/client-go/testing" - sourcesv1alpha2 "knative.dev/eventing/pkg/apis/sources/v1alpha2" + sourcesv1beta1 "knative.dev/eventing/pkg/apis/sources/v1beta1" fakeeventingclient "knative.dev/eventing/pkg/client/injection/client/fake" - "knative.dev/eventing/pkg/client/injection/reconciler/sources/v1alpha2/apiserversource" + "knative.dev/eventing/pkg/client/injection/reconciler/sources/v1beta1/apiserversource" "knative.dev/eventing/pkg/reconciler/apiserversource/resources" reconcilersource "knative.dev/eventing/pkg/reconciler/source" "knative.dev/eventing/pkg/utils" @@ -47,7 +47,7 @@ import ( logtesting "knative.dev/pkg/logging/testing" "knative.dev/pkg/resolver" - rttestingv1alpha1 "knative.dev/eventing/pkg/reconciler/testing" + rttesting "knative.dev/eventing/pkg/reconciler/testing" . "knative.dev/eventing/pkg/reconciler/testing/v1beta1" . "knative.dev/pkg/reconciler/testing" ) @@ -96,16 +96,16 @@ func TestReconcile(t *testing.T) { table := TableTest{{ Name: "not enough permissions", Objects: []runtime.Object{ - rttestingv1alpha1.NewApiServerSource(sourceName, testNS, - rttestingv1alpha1.WithApiServerSourceSpec(sourcesv1alpha2.ApiServerSourceSpec{ - Resources: []sourcesv1alpha2.APIVersionKindSelector{{ + rttesting.NewApiServerSourceV1Beta1(sourceName, testNS, + rttesting.WithApiServerSourceSpecV1B1(sourcesv1beta1.ApiServerSourceSpec{ + Resources: []sourcesv1beta1.APIVersionKindSelector{{ APIVersion: "v1", Kind: "Namespace", }}, SourceSpec: duckv1.SourceSpec{Sink: sinkDest}, }), - rttestingv1alpha1.WithApiServerSourceUID(sourceUID), - rttestingv1alpha1.WithApiServerSourceObjectMetaGeneration(generation), + rttesting.WithApiServerSourceUIDV1B1(sourceUID), + rttesting.WithApiServerSourceObjectMetaGenerationV1B1(generation), ), NewChannel(sinkName, testNS, WithInitChannelConditions, @@ -115,21 +115,21 @@ func TestReconcile(t *testing.T) { }, Key: testNS + "/" + sourceName, WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ - Object: rttestingv1alpha1.NewApiServerSource(sourceName, testNS, - rttestingv1alpha1.WithApiServerSourceSpec(sourcesv1alpha2.ApiServerSourceSpec{ - Resources: []sourcesv1alpha2.APIVersionKindSelector{{ + Object: rttesting.NewApiServerSourceV1Beta1(sourceName, testNS, + rttesting.WithApiServerSourceSpecV1B1(sourcesv1beta1.ApiServerSourceSpec{ + Resources: []sourcesv1beta1.APIVersionKindSelector{{ APIVersion: "v1", Kind: "Namespace", }}, SourceSpec: duckv1.SourceSpec{Sink: sinkDest}, }), - rttestingv1alpha1.WithApiServerSourceUID(sourceUID), - rttestingv1alpha1.WithApiServerSourceObjectMetaGeneration(generation), + rttesting.WithApiServerSourceUIDV1B1(sourceUID), + rttesting.WithApiServerSourceObjectMetaGenerationV1B1(generation), // Status Update: - rttestingv1alpha1.WithInitApiServerSourceConditions, - rttestingv1alpha1.WithApiServerSourceStatusObservedGeneration(generation), - rttestingv1alpha1.WithApiServerSourceSink(sinkURI), - rttestingv1alpha1.WithApiServerSourceNoSufficientPermissions, + rttesting.WithInitApiServerSourceConditionsV1B1, + rttesting.WithApiServerSourceStatusObservedGenerationV1B1(generation), + rttesting.WithApiServerSourceSinkV1B1(sinkURI), + rttesting.WithApiServerSourceNoSufficientPermissionsV1B1, ), }}, WantCreates: []runtime.Object{ @@ -146,16 +146,16 @@ func TestReconcile(t *testing.T) { }, { Name: "valid", Objects: []runtime.Object{ - rttestingv1alpha1.NewApiServerSource(sourceName, testNS, - rttestingv1alpha1.WithApiServerSourceSpec(sourcesv1alpha2.ApiServerSourceSpec{ - Resources: []sourcesv1alpha2.APIVersionKindSelector{{ + rttesting.NewApiServerSourceV1Beta1(sourceName, testNS, + rttesting.WithApiServerSourceSpecV1B1(sourcesv1beta1.ApiServerSourceSpec{ + Resources: []sourcesv1beta1.APIVersionKindSelector{{ APIVersion: "v1", Kind: "Namespace", }}, SourceSpec: duckv1.SourceSpec{Sink: sinkDest}, }), - rttestingv1alpha1.WithApiServerSourceUID(sourceUID), - rttestingv1alpha1.WithApiServerSourceObjectMetaGeneration(generation), + rttesting.WithApiServerSourceUIDV1B1(sourceUID), + rttesting.WithApiServerSourceObjectMetaGenerationV1B1(generation), ), NewChannel(sinkName, testNS, WithInitChannelConditions, @@ -168,23 +168,23 @@ func TestReconcile(t *testing.T) { Eventf(corev1.EventTypeNormal, "ApiServerSourceReconciled", `ApiServerSource reconciled: "%s/%s"`, testNS, sourceName), }, WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ - Object: rttestingv1alpha1.NewApiServerSource(sourceName, testNS, - rttestingv1alpha1.WithApiServerSourceSpec(sourcesv1alpha2.ApiServerSourceSpec{ - Resources: []sourcesv1alpha2.APIVersionKindSelector{{ + Object: rttesting.NewApiServerSourceV1Beta1(sourceName, testNS, + rttesting.WithApiServerSourceSpecV1B1(sourcesv1beta1.ApiServerSourceSpec{ + Resources: []sourcesv1beta1.APIVersionKindSelector{{ APIVersion: "v1", Kind: "Namespace", }}, SourceSpec: duckv1.SourceSpec{Sink: sinkDest}, }), - rttestingv1alpha1.WithApiServerSourceUID(sourceUID), - rttestingv1alpha1.WithApiServerSourceObjectMetaGeneration(generation), + rttesting.WithApiServerSourceUIDV1B1(sourceUID), + rttesting.WithApiServerSourceObjectMetaGenerationV1B1(generation), // Status Update: - rttestingv1alpha1.WithInitApiServerSourceConditions, - rttestingv1alpha1.WithApiServerSourceDeployed, - rttestingv1alpha1.WithApiServerSourceSink(sinkURI), - rttestingv1alpha1.WithApiServerSourceSufficientPermissions, - rttestingv1alpha1.WithApiServerSourceEventTypes(source), - rttestingv1alpha1.WithApiServerSourceStatusObservedGeneration(generation), + rttesting.WithInitApiServerSourceConditionsV1B1, + rttesting.WithApiServerSourceDeployedV1B1, + rttesting.WithApiServerSourceSinkV1B1(sinkURI), + rttesting.WithApiServerSourceSufficientPermissionsV1B1, + rttesting.WithApiServerSourceEventTypesV1B1(source), + rttesting.WithApiServerSourceStatusObservedGenerationV1B1(generation), ), }}, WantCreates: []runtime.Object{ @@ -197,16 +197,16 @@ func TestReconcile(t *testing.T) { }, { Name: "valid with sink URI", Objects: []runtime.Object{ - rttestingv1alpha1.NewApiServerSource(sourceName, testNS, - rttestingv1alpha1.WithApiServerSourceSpec(sourcesv1alpha2.ApiServerSourceSpec{ - Resources: []sourcesv1alpha2.APIVersionKindSelector{{ + rttesting.NewApiServerSourceV1Beta1(sourceName, testNS, + rttesting.WithApiServerSourceSpecV1B1(sourcesv1beta1.ApiServerSourceSpec{ + Resources: []sourcesv1beta1.APIVersionKindSelector{{ APIVersion: "v1", Kind: "Namespace", }}, SourceSpec: duckv1.SourceSpec{Sink: sinkDest}, }), - rttestingv1alpha1.WithApiServerSourceUID(sourceUID), - rttestingv1alpha1.WithApiServerSourceObjectMetaGeneration(generation), + rttesting.WithApiServerSourceUIDV1B1(sourceUID), + rttesting.WithApiServerSourceObjectMetaGenerationV1B1(generation), ), NewChannel(sinkName, testNS, WithInitChannelConditions, @@ -219,23 +219,23 @@ func TestReconcile(t *testing.T) { Eventf(corev1.EventTypeNormal, "ApiServerSourceReconciled", `ApiServerSource reconciled: "%s/%s"`, testNS, sourceName), }, WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ - Object: rttestingv1alpha1.NewApiServerSource(sourceName, testNS, - rttestingv1alpha1.WithApiServerSourceSpec(sourcesv1alpha2.ApiServerSourceSpec{ - Resources: []sourcesv1alpha2.APIVersionKindSelector{{ + Object: rttesting.NewApiServerSourceV1Beta1(sourceName, testNS, + rttesting.WithApiServerSourceSpecV1B1(sourcesv1beta1.ApiServerSourceSpec{ + Resources: []sourcesv1beta1.APIVersionKindSelector{{ APIVersion: "v1", Kind: "Namespace", }}, SourceSpec: duckv1.SourceSpec{Sink: sinkDest}, }), - rttestingv1alpha1.WithApiServerSourceUID(sourceUID), - rttestingv1alpha1.WithApiServerSourceObjectMetaGeneration(generation), + rttesting.WithApiServerSourceUIDV1B1(sourceUID), + rttesting.WithApiServerSourceObjectMetaGenerationV1B1(generation), // Status Update: - rttestingv1alpha1.WithInitApiServerSourceConditions, - rttestingv1alpha1.WithApiServerSourceDeployed, - rttestingv1alpha1.WithApiServerSourceSink(sinkURI), - rttestingv1alpha1.WithApiServerSourceSufficientPermissions, - rttestingv1alpha1.WithApiServerSourceEventTypes(source), - rttestingv1alpha1.WithApiServerSourceStatusObservedGeneration(generation), + rttesting.WithInitApiServerSourceConditionsV1B1, + rttesting.WithApiServerSourceDeployedV1B1, + rttesting.WithApiServerSourceSinkV1B1(sinkURI), + rttesting.WithApiServerSourceSufficientPermissionsV1B1, + rttesting.WithApiServerSourceEventTypesV1B1(source), + rttesting.WithApiServerSourceStatusObservedGenerationV1B1(generation), ), }}, WantCreates: []runtime.Object{ @@ -248,9 +248,9 @@ func TestReconcile(t *testing.T) { }, { Name: "valid with relative uri reference", Objects: []runtime.Object{ - rttestingv1alpha1.NewApiServerSource(sourceName, testNS, - rttestingv1alpha1.WithApiServerSourceSpec(sourcesv1alpha2.ApiServerSourceSpec{ - Resources: []sourcesv1alpha2.APIVersionKindSelector{{ + rttesting.NewApiServerSourceV1Beta1(sourceName, testNS, + rttesting.WithApiServerSourceSpecV1B1(sourcesv1beta1.ApiServerSourceSpec{ + Resources: []sourcesv1beta1.APIVersionKindSelector{{ APIVersion: "v1", Kind: "Namespace", }}, @@ -261,8 +261,8 @@ func TestReconcile(t *testing.T) { }, }, }), - rttestingv1alpha1.WithApiServerSourceUID(sourceUID), - rttestingv1alpha1.WithApiServerSourceObjectMetaGeneration(generation), + rttesting.WithApiServerSourceUIDV1B1(sourceUID), + rttesting.WithApiServerSourceObjectMetaGenerationV1B1(generation), ), NewChannel(sinkName, testNS, WithInitChannelConditions, @@ -275,9 +275,9 @@ func TestReconcile(t *testing.T) { Eventf(corev1.EventTypeNormal, "ApiServerSourceReconciled", `ApiServerSource reconciled: "%s/%s"`, testNS, sourceName), }, WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ - Object: rttestingv1alpha1.NewApiServerSource(sourceName, testNS, - rttestingv1alpha1.WithApiServerSourceSpec(sourcesv1alpha2.ApiServerSourceSpec{ - Resources: []sourcesv1alpha2.APIVersionKindSelector{{ + Object: rttesting.NewApiServerSourceV1Beta1(sourceName, testNS, + rttesting.WithApiServerSourceSpecV1B1(sourcesv1beta1.ApiServerSourceSpec{ + Resources: []sourcesv1beta1.APIVersionKindSelector{{ APIVersion: "v1", Kind: "Namespace", }}, @@ -288,15 +288,15 @@ func TestReconcile(t *testing.T) { }, }, }), - rttestingv1alpha1.WithApiServerSourceUID(sourceUID), - rttestingv1alpha1.WithApiServerSourceObjectMetaGeneration(generation), + rttesting.WithApiServerSourceUIDV1B1(sourceUID), + rttesting.WithApiServerSourceObjectMetaGenerationV1B1(generation), // Status Update: - rttestingv1alpha1.WithInitApiServerSourceConditions, - rttestingv1alpha1.WithApiServerSourceDeployed, - rttestingv1alpha1.WithApiServerSourceSink(sinkTargetURI), - rttestingv1alpha1.WithApiServerSourceSufficientPermissions, - rttestingv1alpha1.WithApiServerSourceEventTypes(source), - rttestingv1alpha1.WithApiServerSourceStatusObservedGeneration(generation), + rttesting.WithInitApiServerSourceConditionsV1B1, + rttesting.WithApiServerSourceDeployedV1B1, + rttesting.WithApiServerSourceSinkV1B1(sinkTargetURI), + rttesting.WithApiServerSourceSufficientPermissionsV1B1, + rttesting.WithApiServerSourceEventTypesV1B1(source), + rttesting.WithApiServerSourceStatusObservedGenerationV1B1(generation), ), }}, WantCreates: []runtime.Object{ @@ -309,16 +309,16 @@ func TestReconcile(t *testing.T) { }, { Name: "deployment update due to env", Objects: []runtime.Object{ - rttestingv1alpha1.NewApiServerSource(sourceName, testNS, - rttestingv1alpha1.WithApiServerSourceSpec(sourcesv1alpha2.ApiServerSourceSpec{ - Resources: []sourcesv1alpha2.APIVersionKindSelector{{ + rttesting.NewApiServerSourceV1Beta1(sourceName, testNS, + rttesting.WithApiServerSourceSpecV1B1(sourcesv1beta1.ApiServerSourceSpec{ + Resources: []sourcesv1beta1.APIVersionKindSelector{{ APIVersion: "v1", Kind: "Namespace", }}, SourceSpec: duckv1.SourceSpec{Sink: sinkDest}, }), - rttestingv1alpha1.WithApiServerSourceUID(sourceUID), - rttestingv1alpha1.WithApiServerSourceObjectMetaGeneration(generation), + rttesting.WithApiServerSourceUIDV1B1(sourceUID), + rttesting.WithApiServerSourceObjectMetaGenerationV1B1(generation), ), NewChannel(sinkName, testNS, WithInitChannelConditions, @@ -332,23 +332,23 @@ func TestReconcile(t *testing.T) { Eventf(corev1.EventTypeNormal, "ApiServerSourceReconciled", `ApiServerSource reconciled: "%s/%s"`, testNS, sourceName), }, WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ - Object: rttestingv1alpha1.NewApiServerSource(sourceName, testNS, - rttestingv1alpha1.WithApiServerSourceSpec(sourcesv1alpha2.ApiServerSourceSpec{ - Resources: []sourcesv1alpha2.APIVersionKindSelector{{ + Object: rttesting.NewApiServerSourceV1Beta1(sourceName, testNS, + rttesting.WithApiServerSourceSpecV1B1(sourcesv1beta1.ApiServerSourceSpec{ + Resources: []sourcesv1beta1.APIVersionKindSelector{{ APIVersion: "v1", Kind: "Namespace", }}, SourceSpec: duckv1.SourceSpec{Sink: sinkDest}, }), - rttestingv1alpha1.WithApiServerSourceUID(sourceUID), - rttestingv1alpha1.WithApiServerSourceObjectMetaGeneration(generation), + rttesting.WithApiServerSourceUIDV1B1(sourceUID), + rttesting.WithApiServerSourceObjectMetaGenerationV1B1(generation), // Status Update: - rttestingv1alpha1.WithInitApiServerSourceConditions, - rttestingv1alpha1.WithApiServerSourceSink(sinkURI), - rttestingv1alpha1.WithApiServerSourceSufficientPermissions, - rttestingv1alpha1.WithApiServerSourceEventTypes(source), - rttestingv1alpha1.WithApiServerSourceDeploymentUnavailable, - rttestingv1alpha1.WithApiServerSourceStatusObservedGeneration(generation), + rttesting.WithInitApiServerSourceConditionsV1B1, + rttesting.WithApiServerSourceSinkV1B1(sinkURI), + rttesting.WithApiServerSourceSufficientPermissionsV1B1, + rttesting.WithApiServerSourceEventTypesV1B1(source), + rttesting.WithApiServerSourceDeploymentUnavailableV1B1, + rttesting.WithApiServerSourceStatusObservedGenerationV1B1(generation), ), }}, WantUpdates: []clientgotesting.UpdateActionImpl{{ @@ -364,9 +364,9 @@ func TestReconcile(t *testing.T) { }, { Name: "deployment update due to service account", Objects: []runtime.Object{ - rttestingv1alpha1.NewApiServerSource(sourceName, testNS, - rttestingv1alpha1.WithApiServerSourceSpec(sourcesv1alpha2.ApiServerSourceSpec{ - Resources: []sourcesv1alpha2.APIVersionKindSelector{{ + rttesting.NewApiServerSourceV1Beta1(sourceName, testNS, + rttesting.WithApiServerSourceSpecV1B1(sourcesv1beta1.ApiServerSourceSpec{ + Resources: []sourcesv1beta1.APIVersionKindSelector{{ APIVersion: "v1", Kind: "Namespace", }}, @@ -375,8 +375,8 @@ func TestReconcile(t *testing.T) { }, ServiceAccountName: "malin", }), - rttestingv1alpha1.WithApiServerSourceUID(sourceUID), - rttestingv1alpha1.WithApiServerSourceObjectMetaGeneration(generation), + rttesting.WithApiServerSourceUIDV1B1(sourceUID), + rttesting.WithApiServerSourceObjectMetaGenerationV1B1(generation), ), NewChannel(sinkName, testNS, WithInitChannelConditions, @@ -390,9 +390,9 @@ func TestReconcile(t *testing.T) { Eventf(corev1.EventTypeNormal, "ApiServerSourceReconciled", `ApiServerSource reconciled: "%s/%s"`, testNS, sourceName), }, WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ - Object: rttestingv1alpha1.NewApiServerSource(sourceName, testNS, - rttestingv1alpha1.WithApiServerSourceSpec(sourcesv1alpha2.ApiServerSourceSpec{ - Resources: []sourcesv1alpha2.APIVersionKindSelector{{ + Object: rttesting.NewApiServerSourceV1Beta1(sourceName, testNS, + rttesting.WithApiServerSourceSpecV1B1(sourcesv1beta1.ApiServerSourceSpec{ + Resources: []sourcesv1beta1.APIVersionKindSelector{{ APIVersion: "v1", Kind: "Namespace", }}, @@ -401,15 +401,15 @@ func TestReconcile(t *testing.T) { }, ServiceAccountName: "malin", }), - rttestingv1alpha1.WithApiServerSourceUID(sourceUID), - rttestingv1alpha1.WithApiServerSourceObjectMetaGeneration(generation), + rttesting.WithApiServerSourceUIDV1B1(sourceUID), + rttesting.WithApiServerSourceObjectMetaGenerationV1B1(generation), // Status Update: - rttestingv1alpha1.WithInitApiServerSourceConditions, - rttestingv1alpha1.WithApiServerSourceDeploymentUnavailable, - rttestingv1alpha1.WithApiServerSourceSink(sinkURI), - rttestingv1alpha1.WithApiServerSourceSufficientPermissions, - rttestingv1alpha1.WithApiServerSourceEventTypes(source), - rttestingv1alpha1.WithApiServerSourceStatusObservedGeneration(generation), + rttesting.WithInitApiServerSourceConditionsV1B1, + rttesting.WithApiServerSourceDeploymentUnavailableV1B1, + rttesting.WithApiServerSourceSinkV1B1(sinkURI), + rttesting.WithApiServerSourceSufficientPermissionsV1B1, + rttesting.WithApiServerSourceEventTypesV1B1(source), + rttesting.WithApiServerSourceStatusObservedGenerationV1B1(generation), ), }}, WantUpdates: []clientgotesting.UpdateActionImpl{{ @@ -425,16 +425,16 @@ func TestReconcile(t *testing.T) { }, { Name: "deployment update due to container count", Objects: []runtime.Object{ - rttestingv1alpha1.NewApiServerSource(sourceName, testNS, - rttestingv1alpha1.WithApiServerSourceSpec(sourcesv1alpha2.ApiServerSourceSpec{ - Resources: []sourcesv1alpha2.APIVersionKindSelector{{ + rttesting.NewApiServerSourceV1Beta1(sourceName, testNS, + rttesting.WithApiServerSourceSpecV1B1(sourcesv1beta1.ApiServerSourceSpec{ + Resources: []sourcesv1beta1.APIVersionKindSelector{{ APIVersion: "v1", Kind: "Namespace", }}, SourceSpec: duckv1.SourceSpec{Sink: sinkDest}, }), - rttestingv1alpha1.WithApiServerSourceUID(sourceUID), - rttestingv1alpha1.WithApiServerSourceObjectMetaGeneration(generation), + rttesting.WithApiServerSourceUIDV1B1(sourceUID), + rttesting.WithApiServerSourceObjectMetaGenerationV1B1(generation), ), NewChannel(sinkName, testNS, WithInitChannelConditions, @@ -448,23 +448,23 @@ func TestReconcile(t *testing.T) { Eventf(corev1.EventTypeNormal, "ApiServerSourceReconciled", `ApiServerSource reconciled: "%s/%s"`, testNS, sourceName), }, WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ - Object: rttestingv1alpha1.NewApiServerSource(sourceName, testNS, - rttestingv1alpha1.WithApiServerSourceSpec(sourcesv1alpha2.ApiServerSourceSpec{ - Resources: []sourcesv1alpha2.APIVersionKindSelector{{ + Object: rttesting.NewApiServerSourceV1Beta1(sourceName, testNS, + rttesting.WithApiServerSourceSpecV1B1(sourcesv1beta1.ApiServerSourceSpec{ + Resources: []sourcesv1beta1.APIVersionKindSelector{{ APIVersion: "v1", Kind: "Namespace", }}, SourceSpec: duckv1.SourceSpec{Sink: sinkDest}, }), - rttestingv1alpha1.WithApiServerSourceUID(sourceUID), - rttestingv1alpha1.WithApiServerSourceObjectMetaGeneration(generation), + rttesting.WithApiServerSourceUIDV1B1(sourceUID), + rttesting.WithApiServerSourceObjectMetaGenerationV1B1(generation), // Status Update: - rttestingv1alpha1.WithInitApiServerSourceConditions, - rttestingv1alpha1.WithApiServerSourceDeploymentUnavailable, - rttestingv1alpha1.WithApiServerSourceSink(sinkURI), - rttestingv1alpha1.WithApiServerSourceSufficientPermissions, - rttestingv1alpha1.WithApiServerSourceEventTypes(source), - rttestingv1alpha1.WithApiServerSourceStatusObservedGeneration(generation), + rttesting.WithInitApiServerSourceConditionsV1B1, + rttesting.WithApiServerSourceDeploymentUnavailableV1B1, + rttesting.WithApiServerSourceSinkV1B1(sinkURI), + rttesting.WithApiServerSourceSufficientPermissionsV1B1, + rttesting.WithApiServerSourceEventTypesV1B1(source), + rttesting.WithApiServerSourceStatusObservedGenerationV1B1(generation), ), }}, WantUpdates: []clientgotesting.UpdateActionImpl{{ @@ -480,16 +480,16 @@ func TestReconcile(t *testing.T) { }, { Name: "valid with broker sink", Objects: []runtime.Object{ - rttestingv1alpha1.NewApiServerSource(sourceName, testNS, - rttestingv1alpha1.WithApiServerSourceSpec(sourcesv1alpha2.ApiServerSourceSpec{ - Resources: []sourcesv1alpha2.APIVersionKindSelector{{ + rttesting.NewApiServerSourceV1Beta1(sourceName, testNS, + rttesting.WithApiServerSourceSpecV1B1(sourcesv1beta1.ApiServerSourceSpec{ + Resources: []sourcesv1beta1.APIVersionKindSelector{{ APIVersion: "v1", Kind: "Namespace", }}, SourceSpec: duckv1.SourceSpec{Sink: brokerDest}, }), - rttestingv1alpha1.WithApiServerSourceUID(sourceUID), - rttestingv1alpha1.WithApiServerSourceObjectMetaGeneration(generation), + rttesting.WithApiServerSourceUIDV1B1(sourceUID), + rttesting.WithApiServerSourceObjectMetaGenerationV1B1(generation), ), NewBroker(sinkName, testNS, WithInitBrokerConditions, @@ -502,23 +502,23 @@ func TestReconcile(t *testing.T) { Eventf(corev1.EventTypeNormal, "ApiServerSourceReconciled", `ApiServerSource reconciled: "%s/%s"`, testNS, sourceName), }, WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ - Object: rttestingv1alpha1.NewApiServerSource(sourceName, testNS, - rttestingv1alpha1.WithApiServerSourceSpec(sourcesv1alpha2.ApiServerSourceSpec{ - Resources: []sourcesv1alpha2.APIVersionKindSelector{{ + Object: rttesting.NewApiServerSourceV1Beta1(sourceName, testNS, + rttesting.WithApiServerSourceSpecV1B1(sourcesv1beta1.ApiServerSourceSpec{ + Resources: []sourcesv1beta1.APIVersionKindSelector{{ APIVersion: "v1", Kind: "Namespace", }}, SourceSpec: duckv1.SourceSpec{Sink: brokerDest}, }), - rttestingv1alpha1.WithApiServerSourceUID(sourceUID), - rttestingv1alpha1.WithApiServerSourceObjectMetaGeneration(generation), + rttesting.WithApiServerSourceUIDV1B1(sourceUID), + rttesting.WithApiServerSourceObjectMetaGenerationV1B1(generation), // Status Update: - rttestingv1alpha1.WithInitApiServerSourceConditions, - rttestingv1alpha1.WithApiServerSourceDeployed, - rttestingv1alpha1.WithApiServerSourceSink(sinkURI), - rttestingv1alpha1.WithApiServerSourceSufficientPermissions, - rttestingv1alpha1.WithApiServerSourceEventTypes(source), - rttestingv1alpha1.WithApiServerSourceStatusObservedGeneration(generation), + rttesting.WithInitApiServerSourceConditionsV1B1, + rttesting.WithApiServerSourceDeployedV1B1, + rttesting.WithApiServerSourceSinkV1B1(sinkURI), + rttesting.WithApiServerSourceSufficientPermissionsV1B1, + rttesting.WithApiServerSourceEventTypesV1B1(source), + rttesting.WithApiServerSourceStatusObservedGenerationV1B1(generation), ), }}, WantCreates: []runtime.Object{ @@ -535,7 +535,7 @@ func TestReconcile(t *testing.T) { ctx = addressable.WithDuck(ctx) r := &Reconciler{ kubeClientSet: fakekubeclient.Get(ctx), - apiserversourceLister: listers.GetApiServerSourceV1alpha2Lister(), + apiserversourceLister: listers.GetApiServerSourceV1beta1Lister(), ceSource: source, receiveAdapterImage: image, sinkResolver: resolver.NewURIResolver(ctx, func(types.NamespacedName) {}), @@ -543,7 +543,7 @@ func TestReconcile(t *testing.T) { configs: &reconcilersource.EmptyVarsGenerator{}, } return apiserversource.NewReconciler(ctx, logger, - fakeeventingclient.Get(ctx), listers.GetApiServerSourceV1alpha2Lister(), + fakeeventingclient.Get(ctx), listers.GetApiServerSourceV1beta1Lister(), controller.GetEventRecorder(ctx), r) }, true, @@ -558,19 +558,19 @@ func makeReceiveAdapter(t *testing.T) *appsv1.Deployment { func makeReceiveAdapterWithName(t *testing.T, sourceName string) *appsv1.Deployment { t.Helper() - src := rttestingv1alpha1.NewApiServerSource(sourceName, testNS, - rttestingv1alpha1.WithApiServerSourceSpec(sourcesv1alpha2.ApiServerSourceSpec{ - Resources: []sourcesv1alpha2.APIVersionKindSelector{{ + src := rttesting.NewApiServerSourceV1Beta1(sourceName, testNS, + rttesting.WithApiServerSourceSpecV1B1(sourcesv1beta1.ApiServerSourceSpec{ + Resources: []sourcesv1beta1.APIVersionKindSelector{{ APIVersion: "v1", Kind: "Namespace", }}, SourceSpec: duckv1.SourceSpec{Sink: sinkDest}, }), - rttestingv1alpha1.WithApiServerSourceUID(sourceUID), + rttesting.WithApiServerSourceUIDV1B1(sourceUID), // Status Update: - rttestingv1alpha1.WithInitApiServerSourceConditions, - rttestingv1alpha1.WithApiServerSourceDeployed, - rttestingv1alpha1.WithApiServerSourceSink(sinkURI), + rttesting.WithInitApiServerSourceConditionsV1B1, + rttesting.WithApiServerSourceDeployedV1B1, + rttesting.WithApiServerSourceSinkV1B1(sinkURI), ) args := resources.ReceiveAdapterArgs{ @@ -589,26 +589,26 @@ func makeReceiveAdapterWithName(t *testing.T, sourceName string) *appsv1.Deploym func makeAvailableReceiveAdapter(t *testing.T) *appsv1.Deployment { ra := makeReceiveAdapter(t) - rttestingv1alpha1.WithDeploymentAvailable()(ra) + rttesting.WithDeploymentAvailable()(ra) return ra } func makeAvailableReceiveAdapterWithTargetURI(t *testing.T) *appsv1.Deployment { t.Helper() - src := rttestingv1alpha1.NewApiServerSource(sourceName, testNS, - rttestingv1alpha1.WithApiServerSourceSpec(sourcesv1alpha2.ApiServerSourceSpec{ - Resources: []sourcesv1alpha2.APIVersionKindSelector{{ + src := rttesting.NewApiServerSourceV1Beta1(sourceName, testNS, + rttesting.WithApiServerSourceSpecV1B1(sourcesv1beta1.ApiServerSourceSpec{ + Resources: []sourcesv1beta1.APIVersionKindSelector{{ APIVersion: "v1", Kind: "Namespace", }}, SourceSpec: duckv1.SourceSpec{Sink: sinkDest}, }), - rttestingv1alpha1.WithApiServerSourceUID(sourceUID), + rttesting.WithApiServerSourceUIDV1B1(sourceUID), // Status Update: - rttestingv1alpha1.WithInitApiServerSourceConditions, - rttestingv1alpha1.WithApiServerSourceDeployed, - rttestingv1alpha1.WithApiServerSourceSink(sinkURI), + rttesting.WithInitApiServerSourceConditionsV1B1, + rttesting.WithApiServerSourceDeployedV1B1, + rttesting.WithApiServerSourceSinkV1B1(sinkURI), ) args := resources.ReceiveAdapterArgs{ @@ -622,7 +622,7 @@ func makeAvailableReceiveAdapterWithTargetURI(t *testing.T) *appsv1.Deployment { ra, err := resources.MakeReceiveAdapter(&args) require.NoError(t, err) - rttestingv1alpha1.WithDeploymentAvailable()(ra) + rttesting.WithDeploymentAvailable()(ra) return ra } diff --git a/pkg/reconciler/apiserversource/controller.go b/pkg/reconciler/apiserversource/controller.go index 65d1d01f1b9..3cf103e8804 100644 --- a/pkg/reconciler/apiserversource/controller.go +++ b/pkg/reconciler/apiserversource/controller.go @@ -32,8 +32,8 @@ import ( kubeclient "knative.dev/pkg/client/injection/kube/client" deploymentinformer "knative.dev/pkg/client/injection/kube/informers/apps/v1/deployment" - apiserversourceinformer "knative.dev/eventing/pkg/client/injection/informers/sources/v1alpha2/apiserversource" - apiserversourcereconciler "knative.dev/eventing/pkg/client/injection/reconciler/sources/v1alpha2/apiserversource" + apiserversourceinformer "knative.dev/eventing/pkg/client/injection/informers/sources/v1beta1/apiserversource" + apiserversourcereconciler "knative.dev/eventing/pkg/client/injection/reconciler/sources/v1beta1/apiserversource" ) // envConfig will be used to extract the required environment variables using diff --git a/pkg/reconciler/apiserversource/controller_test.go b/pkg/reconciler/apiserversource/controller_test.go index c39e7b6b71a..9ee036ff9d9 100644 --- a/pkg/reconciler/apiserversource/controller_test.go +++ b/pkg/reconciler/apiserversource/controller_test.go @@ -30,7 +30,7 @@ import ( _ "knative.dev/pkg/client/injection/kube/informers/apps/v1/deployment/fake" // Fake injection informers - _ "knative.dev/eventing/pkg/client/injection/informers/sources/v1alpha2/apiserversource/fake" + _ "knative.dev/eventing/pkg/client/injection/informers/sources/v1beta1/apiserversource/fake" ) func TestNew(t *testing.T) { diff --git a/pkg/reconciler/apiserversource/resources/receive_adapter.go b/pkg/reconciler/apiserversource/resources/receive_adapter.go index 5ef753536be..bb90469380a 100644 --- a/pkg/reconciler/apiserversource/resources/receive_adapter.go +++ b/pkg/reconciler/apiserversource/resources/receive_adapter.go @@ -29,7 +29,7 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" "knative.dev/eventing/pkg/adapter/apiserver" - "knative.dev/eventing/pkg/apis/sources/v1alpha2" + "knative.dev/eventing/pkg/apis/sources/v1beta1" reconcilersource "knative.dev/eventing/pkg/reconciler/source" "knative.dev/pkg/kmeta" "knative.dev/pkg/system" @@ -39,7 +39,7 @@ import ( // Every field is required. type ReceiveAdapterArgs struct { Image string - Source *v1alpha2.ApiServerSource + Source *v1beta1.ApiServerSource Labels map[string]string SinkURI string Configs reconcilersource.ConfigAccessor diff --git a/pkg/reconciler/apiserversource/resources/receive_adapter_test.go b/pkg/reconciler/apiserversource/resources/receive_adapter_test.go index c3dcaf0fece..d5f7778f9e2 100644 --- a/pkg/reconciler/apiserversource/resources/receive_adapter_test.go +++ b/pkg/reconciler/apiserversource/resources/receive_adapter_test.go @@ -26,7 +26,7 @@ import ( corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "knative.dev/eventing/pkg/apis/sources/v1alpha2" + "knative.dev/eventing/pkg/apis/sources/v1beta1" "knative.dev/eventing/pkg/reconciler/source" duckv1 "knative.dev/pkg/apis/duck/v1" "knative.dev/pkg/kmeta" @@ -40,14 +40,14 @@ func TestMakeReceiveAdapters(t *testing.T) { one := int32(1) trueValue := true - src := &v1alpha2.ApiServerSource{ + src := &v1beta1.ApiServerSource{ ObjectMeta: metav1.ObjectMeta{ Name: name, Namespace: "source-namespace", UID: "1234", }, - Spec: v1alpha2.ApiServerSourceSpec{ - Resources: []v1alpha2.APIVersionKindSelector{{ + Spec: v1beta1.ApiServerSourceSpec{ + Resources: []v1beta1.APIVersionKindSelector{{ APIVersion: "", Kind: "Namespace", }, { @@ -60,7 +60,7 @@ func TestMakeReceiveAdapters(t *testing.T) { MatchLabels: map[string]string{"test-key1": "test-value1"}, }, }}, - ResourceOwner: &v1alpha2.APIVersionKind{ + ResourceOwner: &v1beta1.APIVersionKind{ APIVersion: "custom/v1", Kind: "Parent", }, @@ -79,7 +79,7 @@ func TestMakeReceiveAdapters(t *testing.T) { }, OwnerReferences: []metav1.OwnerReference{ { - APIVersion: "sources.knative.dev/v1alpha2", + APIVersion: "sources.knative.dev/v1beta1", Kind: "ApiServerSource", Name: name, UID: "1234", @@ -167,7 +167,7 @@ func TestMakeReceiveAdapters(t *testing.T) { testCases := map[string]struct { want *appsv1.Deployment - src *v1alpha2.ApiServerSource + src *v1beta1.ApiServerSource }{ "TestMakeReceiveAdapter": { diff --git a/pkg/reconciler/testing/apiserversource.go b/pkg/reconciler/testing/apiserversource.go index 943394000f9..a229ca7d432 100644 --- a/pkg/reconciler/testing/apiserversource.go +++ b/pkg/reconciler/testing/apiserversource.go @@ -24,16 +24,20 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "knative.dev/eventing/pkg/apis/sources/v1alpha2" + "knative.dev/eventing/pkg/apis/sources/v1beta1" "knative.dev/pkg/apis" duckv1 "knative.dev/pkg/apis/duck/v1" "knative.dev/pkg/kmeta" ) -// ApiServerSourceOption enables further configuration of a ApiServer. -type ApiServerSourceOption func(*v1alpha2.ApiServerSource) +// V1Alpha2ApiServerSourceOption enables further configuration of a v1alpha2 ApiServer. +type V1Alpha2ApiServerSourceOption func(*v1alpha2.ApiServerSource) -// NewApiServerSource creates a ApiServer with ApiServerOptions -func NewApiServerSource(name, namespace string, o ...ApiServerSourceOption) *v1alpha2.ApiServerSource { +// V1Beta1ApiServerSourceOption enables further configuration of a v1beta1 ApiServer. +type V1Beta1ApiServerSourceOption func(*v1beta1.ApiServerSource) + +// NewApiServerSourceV1Alpha2 creates a v1alpha2 ApiServer with ApiServerOptions +func NewApiServerSourceV1Alpha2(name, namespace string, o ...V1Alpha2ApiServerSourceOption) *v1alpha2.ApiServerSource { c := &v1alpha2.ApiServerSource{ ObjectMeta: metav1.ObjectMeta{ Name: name, @@ -47,41 +51,56 @@ func NewApiServerSource(name, namespace string, o ...ApiServerSourceOption) *v1a return c } -func WithApiServerSourceUID(uid string) ApiServerSourceOption { - return func(a *v1alpha2.ApiServerSource) { +// NewApiServerSourceV1Beta1 creates a v1beta1 ApiServer with ApiServerOptions +func NewApiServerSourceV1Beta1(name, namespace string, o ...V1Beta1ApiServerSourceOption) *v1beta1.ApiServerSource { + c := &v1beta1.ApiServerSource{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + }, + } + for _, opt := range o { + opt(c) + } + //c.SetDefaults(context.Background()) // TODO: We should add defaults and validation. + return c +} + +func WithApiServerSourceUIDV1B1(uid string) V1Beta1ApiServerSourceOption { + return func(a *v1beta1.ApiServerSource) { a.UID = types.UID(uid) } } -// WithInitApiServerSourceConditions initializes the ApiServerSource's conditions. -func WithInitApiServerSourceConditions(s *v1alpha2.ApiServerSource) { +// WithInitApiServerSourceConditionsV1B1 initializes the v1beta1 ApiServerSource's conditions. +func WithInitApiServerSourceConditionsV1B1(s *v1beta1.ApiServerSource) { s.Status.InitializeConditions() } -func WithApiServerSourceSinkNotFound(s *v1alpha2.ApiServerSource) { +func WithApiServerSourceSinkNotFoundV1B1(s *v1beta1.ApiServerSource) { s.Status.MarkNoSink("NotFound", "") } -func WithApiServerSourceSink(uri *apis.URL) ApiServerSourceOption { - return func(s *v1alpha2.ApiServerSource) { +func WithApiServerSourceSinkV1B1(uri *apis.URL) V1Beta1ApiServerSourceOption { + return func(s *v1beta1.ApiServerSource) { s.Status.MarkSink(uri) } } -func WithApiServerSourceDeploymentUnavailable(s *v1alpha2.ApiServerSource) { +func WithApiServerSourceDeploymentUnavailableV1B1(s *v1beta1.ApiServerSource) { // The Deployment uses GenerateName, so its name is empty. name := kmeta.ChildName(fmt.Sprintf("apiserversource-%s-", s.Name), string(s.GetUID())) s.Status.PropagateDeploymentAvailability(NewDeployment(name, "any")) } -func WithApiServerSourceDeployed(s *v1alpha2.ApiServerSource) { +func WithApiServerSourceDeployedV1B1(s *v1beta1.ApiServerSource) { s.Status.PropagateDeploymentAvailability(NewDeployment("any", "any", WithDeploymentAvailable())) } -func WithApiServerSourceEventTypes(source string) ApiServerSourceOption { - return func(s *v1alpha2.ApiServerSource) { - ceAttributes := make([]duckv1.CloudEventAttributes, 0, len(v1alpha2.ApiServerSourceEventTypes)) - for _, apiServerSourceType := range v1alpha2.ApiServerSourceEventTypes { +func WithApiServerSourceEventTypesV1B1(source string) V1Beta1ApiServerSourceOption { + return func(s *v1beta1.ApiServerSource) { + ceAttributes := make([]duckv1.CloudEventAttributes, 0, len(v1beta1.ApiServerSourceEventTypes)) + for _, apiServerSourceType := range v1beta1.ApiServerSourceEventTypes { ceAttributes = append(ceAttributes, duckv1.CloudEventAttributes{ Type: apiServerSourceType, Source: source, @@ -91,34 +110,41 @@ func WithApiServerSourceEventTypes(source string) ApiServerSourceOption { } } -func WithApiServerSourceSufficientPermissions(s *v1alpha2.ApiServerSource) { +func WithApiServerSourceSufficientPermissionsV1B1(s *v1beta1.ApiServerSource) { s.Status.MarkSufficientPermissions() } -func WithApiServerSourceNoSufficientPermissions(s *v1alpha2.ApiServerSource) { +func WithApiServerSourceNoSufficientPermissionsV1B1(s *v1beta1.ApiServerSource) { s.Status.MarkNoSufficientPermissions("", `User system:serviceaccount:testnamespace:default cannot get, list, watch resource "namespaces" in API group ""`) } -func WithApiServerSourceDeleted(c *v1alpha2.ApiServerSource) { +func WithApiServerSourceDeletedV1B1(c *v1beta1.ApiServerSource) { t := metav1.NewTime(time.Unix(1e9, 0)) c.ObjectMeta.SetDeletionTimestamp(&t) } -func WithApiServerSourceSpec(spec v1alpha2.ApiServerSourceSpec) ApiServerSourceOption { +func WithApiServerSourceSpecV1A2(spec v1alpha2.ApiServerSourceSpec) V1Alpha2ApiServerSourceOption { return func(c *v1alpha2.ApiServerSource) { c.Spec = spec c.Spec.SetDefaults(context.Background()) } } -func WithApiServerSourceStatusObservedGeneration(generation int64) ApiServerSourceOption { - return func(c *v1alpha2.ApiServerSource) { +func WithApiServerSourceSpecV1B1(spec v1beta1.ApiServerSourceSpec) V1Beta1ApiServerSourceOption { + return func(c *v1beta1.ApiServerSource) { + c.Spec = spec + c.Spec.SetDefaults(context.Background()) + } +} + +func WithApiServerSourceStatusObservedGenerationV1B1(generation int64) V1Beta1ApiServerSourceOption { + return func(c *v1beta1.ApiServerSource) { c.Status.ObservedGeneration = generation } } -func WithApiServerSourceObjectMetaGeneration(generation int64) ApiServerSourceOption { - return func(c *v1alpha2.ApiServerSource) { +func WithApiServerSourceObjectMetaGenerationV1B1(generation int64) V1Beta1ApiServerSourceOption { + return func(c *v1beta1.ApiServerSource) { c.ObjectMeta.Generation = generation } } diff --git a/pkg/reconciler/testing/v1beta1/listers.go b/pkg/reconciler/testing/v1beta1/listers.go index a36927e107b..fb79144b2b6 100644 --- a/pkg/reconciler/testing/v1beta1/listers.go +++ b/pkg/reconciler/testing/v1beta1/listers.go @@ -38,6 +38,7 @@ import ( messagingv1beta1 "knative.dev/eventing/pkg/apis/messaging/v1beta1" sourcesv1alpha1 "knative.dev/eventing/pkg/apis/sources/v1alpha1" sourcesv1alpha2 "knative.dev/eventing/pkg/apis/sources/v1alpha2" + sourcesv1beta1 "knative.dev/eventing/pkg/apis/sources/v1beta1" fakeeventingclientset "knative.dev/eventing/pkg/client/clientset/versioned/fake" configslisters "knative.dev/eventing/pkg/client/listers/configs/v1alpha1" eventingv1beta1listers "knative.dev/eventing/pkg/client/listers/eventing/v1beta1" @@ -45,6 +46,7 @@ import ( messaginglistersv1beta1 "knative.dev/eventing/pkg/client/listers/messaging/v1beta1" sourcelisters "knative.dev/eventing/pkg/client/listers/sources/v1alpha1" sourcev1alpha2listers "knative.dev/eventing/pkg/client/listers/sources/v1alpha2" + sourcev1beta1listers "knative.dev/eventing/pkg/client/listers/sources/v1beta1" duckv1 "knative.dev/pkg/apis/duck/v1" "knative.dev/pkg/reconciler/testing" ) @@ -180,6 +182,10 @@ func (l *Listers) GetApiServerSourceV1alpha2Lister() sourcev1alpha2listers.ApiSe return sourcev1alpha2listers.NewApiServerSourceLister(l.indexerFor(&sourcesv1alpha2.ApiServerSource{})) } +func (l *Listers) GetApiServerSourceV1beta1Lister() sourcev1beta1listers.ApiServerSourceLister { + return sourcev1beta1listers.NewApiServerSourceLister(l.indexerFor(&sourcesv1beta1.ApiServerSource{})) +} + func (l *Listers) GetDeploymentLister() appsv1listers.DeploymentLister { return appsv1listers.NewDeploymentLister(l.indexerFor(&appsv1.Deployment{})) } diff --git a/test/e2e/source_api_server_test.go b/test/e2e/source_api_server_v1alpha2_test.go similarity index 95% rename from test/e2e/source_api_server_test.go rename to test/e2e/source_api_server_v1alpha2_test.go index 0c96f1f29a0..561a459a6d3 100644 --- a/test/e2e/source_api_server_test.go +++ b/test/e2e/source_api_server_v1alpha2_test.go @@ -41,7 +41,7 @@ import ( "knative.dev/eventing/test/lib/resources" ) -func TestApiServerSource(t *testing.T) { +func TestApiServerSourceV1Alpha2(t *testing.T) { const ( baseApiServerSourceName = "e2e-api-server-source" @@ -152,13 +152,13 @@ func TestApiServerSource(t *testing.T) { spec := tc.spec spec.Sink = duckv1.Destination{Ref: resources.ServiceKRef(recordEventPodName)} - apiServerSource := eventingtesting.NewApiServerSource( + apiServerSource := eventingtesting.NewApiServerSourceV1Alpha2( fmt.Sprintf("%s-%s", baseApiServerSourceName, tc.name), client.Namespace, - eventingtesting.WithApiServerSourceSpec(spec), + eventingtesting.WithApiServerSourceSpecV1A2(spec), ) - client.CreateApiServerSourceOrFail(apiServerSource) + client.CreateApiServerSourceV1Alpha2OrFail(apiServerSource) // wait for all test resources to be ready client.WaitForAllTestResourcesReadyOrFail() @@ -218,10 +218,10 @@ func TestApiServerSourceV1Alpha2EventTypes(t *testing.T) { client.WaitForResourceReadyOrFail(sugarresources.DefaultBrokerName, testlib.BrokerTypeMeta) // Create the api server source - apiServerSource := eventingtesting.NewApiServerSource( + apiServerSource := eventingtesting.NewApiServerSourceV1Alpha2( sourceName, client.Namespace, - eventingtesting.WithApiServerSourceSpec( + eventingtesting.WithApiServerSourceSpecV1A2( sourcesv1alpha2.ApiServerSourceSpec{ Resources: []sourcesv1alpha2.APIVersionKindSelector{{ APIVersion: "v1", @@ -234,7 +234,7 @@ func TestApiServerSourceV1Alpha2EventTypes(t *testing.T) { ) apiServerSource.Spec.Sink = duckv1.Destination{Ref: &duckv1.KReference{APIVersion: "eventing.knative.dev/v1beta1", Kind: "Broker", Name: sugarresources.DefaultBrokerName, Namespace: client.Namespace}} - client.CreateApiServerSourceOrFail(apiServerSource) + client.CreateApiServerSourceV1Alpha2OrFail(apiServerSource) // wait for all test resources to be ready client.WaitForAllTestResourcesReadyOrFail() diff --git a/test/e2e/source_api_server_v1beta1_test.go b/test/e2e/source_api_server_v1beta1_test.go new file mode 100644 index 00000000000..1a504f877e3 --- /dev/null +++ b/test/e2e/source_api_server_v1beta1_test.go @@ -0,0 +1,257 @@ +// +build e2e + +/* +Copyright 2019 The Knative Authors +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package e2e + +import ( + "fmt" + "testing" + "time" + + "knative.dev/eventing/pkg/reconciler/sugar" + + sugarresources "knative.dev/eventing/pkg/reconciler/sugar/resources" + + cetest "github.com/cloudevents/sdk-go/v2/test" + corev1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/sets" + + duckv1 "knative.dev/pkg/apis/duck/v1" + + sourcesv1beta1 "knative.dev/eventing/pkg/apis/sources/v1beta1" + eventingtesting "knative.dev/eventing/pkg/reconciler/testing" + testlib "knative.dev/eventing/test/lib" + "knative.dev/eventing/test/lib/recordevents" + "knative.dev/eventing/test/lib/resources" +) + +func TestApiServerSourceV1Beta1(t *testing.T) { + const ( + baseApiServerSourceName = "e2e-api-server-source" + + roleName = "event-watcher-r" + serviceAccountName = "event-watcher-sa" + baseHelloworldPodName = "e2e-api-server-source-helloworld-pod" + baseLoggerPodName = "e2e-api-server-source-logger-pod" + ) + + mode := "Reference" + table := []struct { + name string + spec sourcesv1beta1.ApiServerSourceSpec + pod func(name string) *corev1.Pod + expected string + }{ + { + name: "event-ref", + spec: sourcesv1beta1.ApiServerSourceSpec{ + Resources: []sourcesv1beta1.APIVersionKindSelector{{ + APIVersion: "v1", + Kind: "Event", + }}, + EventMode: mode, + ServiceAccountName: serviceAccountName, + }, + pod: func(name string) *corev1.Pod { return resources.HelloWorldPod(name) }, + expected: "Event", + }, + { + name: "event-ref-unmatch-label", + spec: sourcesv1beta1.ApiServerSourceSpec{ + Resources: []sourcesv1beta1.APIVersionKindSelector{{ + APIVersion: "v1", + Kind: "Pod", + LabelSelector: &metav1.LabelSelector{MatchLabels: map[string]string{"e2e": "testing"}}, + }}, + EventMode: mode, + ServiceAccountName: serviceAccountName, + }, + pod: func(name string) *corev1.Pod { return resources.HelloWorldPod(name) }, + }, + { + name: "event-ref-match-label", + spec: sourcesv1beta1.ApiServerSourceSpec{ + Resources: []sourcesv1beta1.APIVersionKindSelector{{ + APIVersion: "v1", + Kind: "Pod", + LabelSelector: &metav1.LabelSelector{MatchLabels: map[string]string{"e2e": "testing"}}, + }}, + EventMode: mode, + ServiceAccountName: serviceAccountName, + }, + pod: func(name string) *corev1.Pod { + return resources.HelloWorldPod(name, resources.WithLabelsForPod(map[string]string{"e2e": "testing"})) + }, + expected: "Pod", + }, + { + name: "event-ref-match-label-expr", + spec: sourcesv1beta1.ApiServerSourceSpec{ + Resources: []sourcesv1beta1.APIVersionKindSelector{{ + APIVersion: "v1", + Kind: "Pod", + LabelSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"e2e": "testing"}, + MatchExpressions: []metav1.LabelSelectorRequirement{{Key: "e2e", Operator: "Exists"}}, + }, + }}, + EventMode: mode, + ServiceAccountName: serviceAccountName, + }, + pod: func(name string) *corev1.Pod { + return resources.HelloWorldPod(name, resources.WithLabelsForPod(map[string]string{"e2e": "testing"})) + }, + expected: "Pod", + }, + } + + for _, tc := range table { + tc := tc // capture range variable + t.Run(tc.name, func(t *testing.T) { + // Setup client + client := setup(t, true) + defer tearDown(client) + + // creates ServiceAccount and RoleBinding with a role for reading pods and events + r := resources.Role(roleName, + resources.WithRuleForRole(&rbacv1.PolicyRule{ + APIGroups: []string{""}, + Resources: []string{"events", "pods"}, + Verbs: []string{"get", "list", "watch"}})) + client.CreateServiceAccountOrFail(serviceAccountName) + client.CreateRoleOrFail(r) + client.CreateRoleBindingOrFail( + serviceAccountName, + testlib.RoleKind, + roleName, + fmt.Sprintf("%s-%s", serviceAccountName, roleName), + client.Namespace, + ) + + // create event record + recordEventPodName := fmt.Sprintf("%s-%s", baseLoggerPodName, tc.name) + eventTracker, _ := recordevents.StartEventRecordOrFail(client, recordEventPodName) + defer eventTracker.Cleanup() + + spec := tc.spec + spec.Sink = duckv1.Destination{Ref: resources.ServiceKRef(recordEventPodName)} + + apiServerSource := eventingtesting.NewApiServerSourceV1Beta1( + fmt.Sprintf("%s-%s", baseApiServerSourceName, tc.name), + client.Namespace, + eventingtesting.WithApiServerSourceSpecV1B1(spec), + ) + + client.CreateApiServerSourceV1Beta1OrFail(apiServerSource) + + // wait for all test resources to be ready + client.WaitForAllTestResourcesReadyOrFail() + + helloworldPod := tc.pod(fmt.Sprintf("%s-%s", baseHelloworldPodName, tc.name)) + client.CreatePodOrFail(helloworldPod) + + // verify the logger service receives the event(s) + // TODO(chizhg): right now it's only doing a very basic check by looking for the tc.data word, + // we can add a json matcher to improve it in the future. + + // Run asserts + if tc.expected == "" { + time.Sleep(10 * time.Second) + eventTracker.AssertNot(recordevents.Any()) + } else { + eventTracker.AssertAtLeast(1, recordevents.MatchEvent( + cetest.DataContains(tc.expected), + )) + } + }) + } +} + +func TestApiServerSourceV1Beta1EventTypes(t *testing.T) { + const ( + sourceName = "e2e-apiserver-source-eventtypes" + serviceAccountName = "event-watcher-sa" + roleName = "event-watcher-r" + ) + + client := setup(t, true) + defer tearDown(client) + + // creates ServiceAccount and RoleBinding with a role for reading pods and events + r := resources.Role(roleName, + resources.WithRuleForRole(&rbacv1.PolicyRule{ + APIGroups: []string{""}, + Resources: []string{"events", "pods"}, + Verbs: []string{"get", "list", "watch"}})) + client.CreateServiceAccountOrFail(serviceAccountName) + client.CreateRoleOrFail(r) + client.CreateRoleBindingOrFail( + serviceAccountName, + testlib.RoleKind, + roleName, + fmt.Sprintf("%s-%s", serviceAccountName, roleName), + client.Namespace, + ) + + // Label namespace so that it creates the default broker. + if err := client.LabelNamespace(map[string]string{sugar.InjectionLabelKey: sugar.InjectionEnabledLabelValue}); err != nil { + t.Fatalf("Error annotating namespace: %v", err) + } + + // Wait for default broker ready. + client.WaitForResourceReadyOrFail(sugarresources.DefaultBrokerName, testlib.BrokerTypeMeta) + + // Create the api server source + apiServerSource := eventingtesting.NewApiServerSourceV1Beta1( + sourceName, + client.Namespace, + eventingtesting.WithApiServerSourceSpecV1B1( + sourcesv1beta1.ApiServerSourceSpec{ + Resources: []sourcesv1beta1.APIVersionKindSelector{{ + APIVersion: "v1", + Kind: "Event", + }}, + EventMode: "Reference", + ServiceAccountName: serviceAccountName, + // TODO change sink to be a non-Broker one once we revisit EventType https://github.com/knative/eventing/issues/2750 + }), + ) + apiServerSource.Spec.Sink = duckv1.Destination{Ref: &duckv1.KReference{APIVersion: "eventing.knative.dev/v1beta1", Kind: "Broker", Name: sugarresources.DefaultBrokerName, Namespace: client.Namespace}} + + client.CreateApiServerSourceV1Beta1OrFail(apiServerSource) + + // wait for all test resources to be ready + client.WaitForAllTestResourcesReadyOrFail() + + // verify that EventTypes were created. + eventTypes, err := client.Eventing.EventingV1beta1().EventTypes(client.Namespace).List(metav1.ListOptions{}) + if err != nil { + t.Fatalf("Error retrieving EventTypes: %v", err) + } + if len(eventTypes.Items) != len(sourcesv1beta1.ApiServerSourceEventTypes) { + t.Fatalf("Invalid number of EventTypes registered for ApiServerSource: %s/%s, expected: %d, got: %d", client.Namespace, sourceName, len(sourcesv1beta1.ApiServerSourceEventTypes), len(eventTypes.Items)) + } + + expectedCeTypes := sets.NewString(sourcesv1beta1.ApiServerSourceEventTypes...) + for _, et := range eventTypes.Items { + if !expectedCeTypes.Has(et.Spec.Type) { + t.Fatalf("Invalid spec.type for ApiServerSource EventType, expected one of: %v, got: %s", sourcesv1beta1.ApiServerSourceEventTypes, et.Spec.Type) + } + } +} diff --git a/test/lib/creation.go b/test/lib/creation.go index 078192a34a0..7258d1e6d79 100644 --- a/test/lib/creation.go +++ b/test/lib/creation.go @@ -333,8 +333,8 @@ func (c *Client) CreateSinkBindingV1Beta1OrFail(sb *sourcesv1beta1.SinkBinding) c.Tracker.AddObj(sb) } -// CreateApiServerSourceOrFail will create an ApiServerSource -func (c *Client) CreateApiServerSourceOrFail(apiServerSource *sourcesv1alpha2.ApiServerSource) { +// CreateApiServerSourceV1Alpha2OrFail will create an v1alpha2 ApiServerSource +func (c *Client) CreateApiServerSourceV1Alpha2OrFail(apiServerSource *sourcesv1alpha2.ApiServerSource) { c.T.Logf("Creating apiserversource %+v", apiServerSource) apiServerInterface := c.Eventing.SourcesV1alpha2().ApiServerSources(c.Namespace) _, err := apiServerInterface.Create(apiServerSource) @@ -344,6 +344,17 @@ func (c *Client) CreateApiServerSourceOrFail(apiServerSource *sourcesv1alpha2.Ap c.Tracker.AddObj(apiServerSource) } +// CreateApiServerSourceV1Beta1OrFail will create an v1beta1 ApiServerSource +func (c *Client) CreateApiServerSourceV1Beta1OrFail(apiServerSource *sourcesv1beta1.ApiServerSource) { + c.T.Logf("Creating apiserversource %+v", apiServerSource) + apiServerInterface := c.Eventing.SourcesV1beta1().ApiServerSources(c.Namespace) + _, err := apiServerInterface.Create(apiServerSource) + if err != nil { + c.T.Fatalf("Failed to create apiserversource %q: %v", apiServerSource.Name, err) + } + c.Tracker.AddObj(apiServerSource) +} + // CreateContainerSourceV1Alpha2OrFail will create a ContainerSource. func (c *Client) CreateContainerSourceV1Alpha2OrFail(containerSource *sourcesv1alpha2.ContainerSource) { c.T.Logf("Creating containersource %+v", containerSource) From c768c32d8afa3a0de666ef5cc66320161d55d00a Mon Sep 17 00:00:00 2001 From: capri-xiyue <52932582+capri-xiyue@users.noreply.github.com> Date: Fri, 17 Jul 2020 19:40:45 +0000 Subject: [PATCH 8/8] Update test/e2e/source_api_server_v1beta1_test.go Co-authored-by: Matt Moore --- test/e2e/source_api_server_v1beta1_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/source_api_server_v1beta1_test.go b/test/e2e/source_api_server_v1beta1_test.go index 1a504f877e3..80c00635127 100644 --- a/test/e2e/source_api_server_v1beta1_test.go +++ b/test/e2e/source_api_server_v1beta1_test.go @@ -1,7 +1,7 @@ // +build e2e /* -Copyright 2019 The Knative Authors +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