From d48f304cf478c0a4fcafe032988f6a052f5ee76c Mon Sep 17 00:00:00 2001 From: danyinggu Date: Tue, 1 Sep 2020 16:49:16 -0400 Subject: [PATCH] Promote CloudBuildSource to v1 API (#1657) * Promote CloudBuildSource to v1 API * fix format --- .../events/v1/cloudbuildsource_defaults.go | 37 ++ .../v1/cloudbuildsource_defaults_test.go | 134 +++++ .../events/v1/cloudbuildsource_lifecycle.go | 41 ++ .../v1/cloudbuildsource_lifecycle_test.go | 159 ++++++ pkg/apis/events/v1/cloudbuildsource_types.go | 120 +++++ .../events/v1/cloudbuildsource_types_test.go | 109 ++++ .../events/v1/cloudbuildsource_validation.go | 77 +++ .../v1/cloudbuildsource_validation_test.go | 488 ++++++++++++++++++ pkg/apis/events/v1/implements_test.go | 11 +- pkg/apis/events/v1/register.go | 2 + pkg/apis/events/v1/register_test.go | 1 + pkg/apis/events/v1/zz_generated.deepcopy.go | 95 ++++ .../typed/events/v1/cloudbuildsource.go | 191 +++++++ .../typed/events/v1/events_client.go | 5 + .../events/v1/fake/fake_cloudbuildsource.go | 140 +++++ .../events/v1/fake/fake_events_client.go | 4 + .../typed/events/v1/generated_expansion.go | 2 + .../events/v1/cloudbuildsource.go | 89 ++++ .../externalversions/events/v1/interface.go | 7 + .../informers/externalversions/generic.go | 2 + .../v1/cloudbuildsource/cloudbuildsource.go | 52 ++ .../events/v1/cloudbuildsource/fake/fake.go | 40 ++ .../events/v1/cloudbuildsource/controller.go | 142 +++++ .../events/v1/cloudbuildsource/reconciler.go | 449 ++++++++++++++++ .../events/v1/cloudbuildsource/state.go | 106 ++++ .../listers/events/v1/cloudbuildsource.go | 94 ++++ .../listers/events/v1/expansion_generated.go | 8 + 27 files changed, 2604 insertions(+), 1 deletion(-) create mode 100644 pkg/apis/events/v1/cloudbuildsource_defaults.go create mode 100644 pkg/apis/events/v1/cloudbuildsource_defaults_test.go create mode 100644 pkg/apis/events/v1/cloudbuildsource_lifecycle.go create mode 100644 pkg/apis/events/v1/cloudbuildsource_lifecycle_test.go create mode 100644 pkg/apis/events/v1/cloudbuildsource_types.go create mode 100644 pkg/apis/events/v1/cloudbuildsource_types_test.go create mode 100644 pkg/apis/events/v1/cloudbuildsource_validation.go create mode 100644 pkg/apis/events/v1/cloudbuildsource_validation_test.go create mode 100644 pkg/client/clientset/versioned/typed/events/v1/cloudbuildsource.go create mode 100644 pkg/client/clientset/versioned/typed/events/v1/fake/fake_cloudbuildsource.go create mode 100644 pkg/client/informers/externalversions/events/v1/cloudbuildsource.go create mode 100644 pkg/client/injection/informers/events/v1/cloudbuildsource/cloudbuildsource.go create mode 100644 pkg/client/injection/informers/events/v1/cloudbuildsource/fake/fake.go create mode 100644 pkg/client/injection/reconciler/events/v1/cloudbuildsource/controller.go create mode 100644 pkg/client/injection/reconciler/events/v1/cloudbuildsource/reconciler.go create mode 100644 pkg/client/injection/reconciler/events/v1/cloudbuildsource/state.go create mode 100644 pkg/client/listers/events/v1/cloudbuildsource.go diff --git a/pkg/apis/events/v1/cloudbuildsource_defaults.go b/pkg/apis/events/v1/cloudbuildsource_defaults.go new file mode 100644 index 0000000000..84fb16691a --- /dev/null +++ b/pkg/apis/events/v1/cloudbuildsource_defaults.go @@ -0,0 +1,37 @@ +/* +Copyright 2020 Google LLC. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT 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 v1 + +import ( + "context" + + "knative.dev/pkg/apis" + + "github.com/google/knative-gcp/pkg/apis/duck" + metadataClient "github.com/google/knative-gcp/pkg/gclient/metadata" +) + +func (bs *CloudBuildSource) SetDefaults(ctx context.Context) { + ctx = apis.WithinParent(ctx, bs.ObjectMeta) + bs.Spec.SetDefaults(ctx) + duck.SetClusterNameAnnotation(&bs.ObjectMeta, metadataClient.NewDefaultMetadataClient()) + duck.SetAutoscalingAnnotationsDefaults(ctx, &bs.ObjectMeta) +} + +func (bss *CloudBuildSourceSpec) SetDefaults(ctx context.Context) { + bss.SetPubSubDefaults(ctx) +} diff --git a/pkg/apis/events/v1/cloudbuildsource_defaults_test.go b/pkg/apis/events/v1/cloudbuildsource_defaults_test.go new file mode 100644 index 0000000000..eb6368ef9e --- /dev/null +++ b/pkg/apis/events/v1/cloudbuildsource_defaults_test.go @@ -0,0 +1,134 @@ +/* +Copyright 2020 Google LLC. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT 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 v1 + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + gcpauthtesthelper "github.com/google/knative-gcp/pkg/apis/configs/gcpauth/testhelper" + "github.com/google/knative-gcp/pkg/apis/duck" + duckv1 "github.com/google/knative-gcp/pkg/apis/duck/v1" + testingMetadataClient "github.com/google/knative-gcp/pkg/gclient/metadata/testing" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func TestBuildSourceDefaults(t *testing.T) { + tests := []struct { + name string + start *CloudBuildSource + want *CloudBuildSource + }{{ + name: "defaults present", + start: &CloudBuildSource{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + duck.ClusterNameAnnotation: testingMetadataClient.FakeClusterName, + }, + }, + Spec: CloudBuildSourceSpec{ + PubSubSpec: duckv1.PubSubSpec{ + Secret: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: "my-cloud-key", + }, + Key: "test.json", + }, + }, + }, + }, + want: &CloudBuildSource{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + duck.ClusterNameAnnotation: testingMetadataClient.FakeClusterName, + }, + }, + Spec: CloudBuildSourceSpec{ + PubSubSpec: duckv1.PubSubSpec{ + Secret: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: "my-cloud-key", + }, + Key: "test.json", + }, + }, + }, + }, + }, { + // Due to the limitation mentioned in https://github.com/google/knative-gcp/issues/1037, specifying the cluster name annotation. + name: "missing defaults, except cluster name annotations", + start: &CloudBuildSource{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + duck.ClusterNameAnnotation: testingMetadataClient.FakeClusterName, + }, + }, + Spec: CloudBuildSourceSpec{}, + }, + want: &CloudBuildSource{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + duck.ClusterNameAnnotation: testingMetadataClient.FakeClusterName, + }, + }, + Spec: CloudBuildSourceSpec{ + PubSubSpec: duckv1.PubSubSpec{ + Secret: &gcpauthtesthelper.Secret, + }, + }, + }, + }} + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := test.start + got.SetDefaults(gcpauthtesthelper.ContextWithDefaults()) + + if diff := cmp.Diff(test.want, got); diff != "" { + t.Errorf("failed to get expected (-want, +got) = %v", diff) + } + }) + } +} + +func TestCloudBuildSourceDefaults_NoChange(t *testing.T) { + want := &CloudBuildSource{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + duck.ClusterNameAnnotation: testingMetadataClient.FakeClusterName, + }, + }, + Spec: CloudBuildSourceSpec{ + PubSubSpec: duckv1.PubSubSpec{ + Secret: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: "my-cloud-key", + }, + Key: "test.json", + }, + }, + }, + } + + got := want.DeepCopy() + got.SetDefaults(gcpauthtesthelper.ContextWithDefaults()) + if diff := cmp.Diff(want, got); diff != "" { + t.Errorf("failed to get expected (-want, +got) = %v", diff) + } +} diff --git a/pkg/apis/events/v1/cloudbuildsource_lifecycle.go b/pkg/apis/events/v1/cloudbuildsource_lifecycle.go new file mode 100644 index 0000000000..ea55423edc --- /dev/null +++ b/pkg/apis/events/v1/cloudbuildsource_lifecycle.go @@ -0,0 +1,41 @@ +/* +Copyright 2020 Google LLC. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT 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 v1 + +import ( + "knative.dev/pkg/apis" +) + +// GetCondition returns the condition currently associated with the given type, or nil. +func (bs *CloudBuildSourceStatus) GetCondition(t apis.ConditionType) *apis.Condition { + return buildCondSet.Manage(bs).GetCondition(t) +} + +// GetTopLevelCondition returns the top level condition. +func (bs *CloudBuildSourceStatus) GetTopLevelCondition() *apis.Condition { + return buildCondSet.Manage(bs).GetTopLevelCondition() +} + +// IsReady returns true if the resource is ready overall. +func (bs *CloudBuildSourceStatus) IsReady() bool { + return buildCondSet.Manage(bs).IsHappy() +} + +// InitializeConditions sets relevant unset conditions to Unknown state. +func (bs *CloudBuildSourceStatus) InitializeConditions() { + buildCondSet.Manage(bs).InitializeConditions() +} diff --git a/pkg/apis/events/v1/cloudbuildsource_lifecycle_test.go b/pkg/apis/events/v1/cloudbuildsource_lifecycle_test.go new file mode 100644 index 0000000000..5cf8dda8ba --- /dev/null +++ b/pkg/apis/events/v1/cloudbuildsource_lifecycle_test.go @@ -0,0 +1,159 @@ +/* +Copyright 2020 Google LLC. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT 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 v1 + +import ( + "testing" + + duckv1 "github.com/google/knative-gcp/pkg/apis/duck/v1" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + corev1 "k8s.io/api/core/v1" + "knative.dev/pkg/apis" +) + +func TestCloudBuildSourceStatusIsReady(t *testing.T) { + tests := []struct { + name string + s *CloudBuildSourceStatus + wantConditionStatus corev1.ConditionStatus + want bool + }{ + { + name: "uninitialized", + s: &CloudBuildSourceStatus{}, + want: false, + }, { + name: "initialized", + s: func() *CloudBuildSourceStatus { + s := &CloudBuildSource{} + s.Status.InitializeConditions() + return &s.Status + }(), + wantConditionStatus: corev1.ConditionUnknown, + want: false, + }, + { + name: "the status of pullsubscription is false", + s: func() *CloudBuildSourceStatus { + s := &CloudBuildSource{} + s.Status.InitializeConditions() + s.Status.MarkPullSubscriptionFailed(s.ConditionSet(), "PullSubscriptionFalse", "status false test message") + return &s.Status + }(), + wantConditionStatus: corev1.ConditionFalse, + }, { + name: "the status of pullsubscription is unknown", + s: func() *CloudBuildSourceStatus { + s := &CloudBuildSource{} + s.Status.InitializeConditions() + s.Status.MarkPullSubscriptionUnknown(s.ConditionSet(), "PullSubscriptionUnknown", "status unknown test message") + return &s.Status + }(), + wantConditionStatus: corev1.ConditionUnknown, + }, + { + name: "ready", + s: func() *CloudBuildSourceStatus { + s := &CloudBuildSource{} + s.Status.InitializeConditions() + s.Status.MarkPullSubscriptionReady(s.ConditionSet()) + return &s.Status + }(), + wantConditionStatus: corev1.ConditionTrue, + want: true, + }} + 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 TestCloudBuildSourceStatusGetCondition(t *testing.T) { + tests := []struct { + name string + s *CloudBuildSourceStatus + condQuery apis.ConditionType + want *apis.Condition + }{{ + name: "uninitialized", + s: &CloudBuildSourceStatus{}, + condQuery: CloudBuildSourceConditionReady, + want: nil, + }, { + name: "initialized", + s: func() *CloudBuildSourceStatus { + s := &CloudBuildSourceStatus{} + s.InitializeConditions() + return s + }(), + condQuery: CloudBuildSourceConditionReady, + want: &apis.Condition{ + Type: CloudBuildSourceConditionReady, + Status: corev1.ConditionUnknown, + }, + }, { + name: "not ready", + + s: func() *CloudBuildSourceStatus { + s := &CloudBuildSource{} + s.Status.InitializeConditions() + s.Status.MarkPullSubscriptionFailed(s.ConditionSet(), "NotReady", "test message") + return &s.Status + }(), + condQuery: duckv1.PullSubscriptionReady, + want: &apis.Condition{ + Type: duckv1.PullSubscriptionReady, + Status: corev1.ConditionFalse, + Reason: "NotReady", + Message: "test message", + }, + }, { + name: "ready", + s: func() *CloudBuildSourceStatus { + s := &CloudBuildSource{} + s.Status.InitializeConditions() + s.Status.MarkPullSubscriptionReady(s.ConditionSet()) + return &s.Status + }(), + condQuery: duckv1.PullSubscriptionReady, + want: &apis.Condition{ + Type: duckv1.PullSubscriptionReady, + Status: corev1.ConditionTrue, + }, + }} + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := test.s.GetCondition(test.condQuery) + ignoreTime := cmpopts.IgnoreFields(apis.Condition{}, + "LastTransitionTime", "Severity") + if diff := cmp.Diff(test.want, got, ignoreTime); diff != "" { + t.Errorf("unexpected condition (-want, +got) = %v", diff) + } + }) + } +} diff --git a/pkg/apis/events/v1/cloudbuildsource_types.go b/pkg/apis/events/v1/cloudbuildsource_types.go new file mode 100644 index 0000000000..20b5ab306e --- /dev/null +++ b/pkg/apis/events/v1/cloudbuildsource_types.go @@ -0,0 +1,120 @@ +/* +Copyright 2020 Google LLC +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT 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 v1 + +import ( + gcpduckv1 "github.com/google/knative-gcp/pkg/apis/duck/v1" + kngcpduckv1 "github.com/google/knative-gcp/pkg/duck/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "knative.dev/pkg/apis/duck" + "knative.dev/pkg/kmeta" + "knative.dev/pkg/webhook/resourcesemantics" + + "k8s.io/apimachinery/pkg/runtime/schema" + "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" +) + +// CloudBuildSource is a specification for a CloudBuildSource resource +// +genclient +// +genreconciler +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +type CloudBuildSource struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec CloudBuildSourceSpec `json:"spec,omitempty"` + Status CloudBuildSourceStatus `json:"status,omitempty"` +} + +var ( + _ kmeta.OwnerRefable = (*CloudBuildSource)(nil) + _ resourcesemantics.GenericCRD = (*CloudBuildSource)(nil) + _ kngcpduckv1.PubSubable = (*CloudBuildSource)(nil) + _ kngcpduckv1.Identifiable = (*CloudBuildSource)(nil) + _ = duck.VerifyType(&CloudBuildSource{}, &duckv1.Conditions{}) + _ duckv1.KRShaped = (*CloudBuildSource)(nil) +) + +// CloudBuildSourceSpec defines the desired state of the CloudBuildSource. +type CloudBuildSourceSpec struct { + // This brings in the PubSub based Source Specs. Includes: + // Sink, CloudEventOverrides, Secret and Project. + gcpduckv1.PubSubSpec `json:",inline"` +} + +const ( + // CloudBuildSourceConditionReady has status True when the CloudBuildSource is + // ready to send events. + CloudBuildSourceConditionReady = apis.ConditionReady +) + +var buildCondSet = apis.NewLivingConditionSet( + gcpduckv1.PullSubscriptionReady, +) + +// CloudBuildSourceStatus defines the observed state of CloudBuildSource. +type CloudBuildSourceStatus struct { + gcpduckv1.PubSubStatus `json:",inline"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// CloudBuildSourceList contains a list of CloudBuildSources. +type CloudBuildSourceList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []CloudBuildSource `json:"items"` +} + +// Methods for pubsubable interface +func (*CloudBuildSource) GetGroupVersionKind() schema.GroupVersionKind { + return SchemeGroupVersion.WithKind("CloudBuildSource") +} + +// Methods for identifiable interface. +// IdentitySpec returns the IdentitySpec portion of the Spec. +func (s *CloudBuildSource) IdentitySpec() *gcpduckv1.IdentitySpec { + return &s.Spec.IdentitySpec +} + +// IdentityStatus returns the IdentityStatus portion of the Status. +func (s *CloudBuildSource) IdentityStatus() *gcpduckv1.IdentityStatus { + return &s.Status.IdentityStatus +} + +// CloudBuildSourceSpec returns the CloudBuildSourceSpec portion of the Spec. +func (bs *CloudBuildSource) PubSubSpec() *gcpduckv1.PubSubSpec { + return &bs.Spec.PubSubSpec +} + +// PubSubStatus returns the PubSubStatus portion of the Status. +func (bs *CloudBuildSource) PubSubStatus() *gcpduckv1.PubSubStatus { + return &bs.Status.PubSubStatus +} + +// ConditionSet returns the apis.ConditionSet of the embedding object. +func (bs *CloudBuildSource) ConditionSet() *apis.ConditionSet { + return &buildCondSet +} + +// GetConditionSet retrieves the condition set for this resource. Implements the KRShaped interface. +func (*CloudBuildSource) GetConditionSet() apis.ConditionSet { + return buildCondSet +} + +// GetStatus retrieves the status of the CloudBuildSource. Implements the KRShaped interface. +func (s *CloudBuildSource) GetStatus() *duckv1.Status { + return &s.Status.Status +} diff --git a/pkg/apis/events/v1/cloudbuildsource_types_test.go b/pkg/apis/events/v1/cloudbuildsource_types_test.go new file mode 100644 index 0000000000..7871f3e47f --- /dev/null +++ b/pkg/apis/events/v1/cloudbuildsource_types_test.go @@ -0,0 +1,109 @@ +/* +Copyright 2020 Google LLC +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT 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 v1 + +import ( + "testing" + + "github.com/google/go-cmp/cmp/cmpopts" + "knative.dev/pkg/apis" + + "github.com/google/go-cmp/cmp" + v1 "github.com/google/knative-gcp/pkg/apis/duck/v1" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +func TestCloudBuildSourceGetGroupVersionKind(t *testing.T) { + want := schema.GroupVersionKind{ + Group: "events.cloud.google.com", + Version: "v1", + Kind: "CloudBuildSource", + } + + c := &CloudBuildSource{} + got := c.GetGroupVersionKind() + + if diff := cmp.Diff(want, got); diff != "" { + t.Errorf("failed to get expected (-want, +got) = %v", diff) + } +} + +func TestCloudBuildSourceIdentitySpec(t *testing.T) { + s := &CloudBuildSource{ + Spec: CloudBuildSourceSpec{ + PubSubSpec: v1.PubSubSpec{ + IdentitySpec: v1.IdentitySpec{ + ServiceAccountName: "test", + }, + }, + }, + } + want := "test" + got := s.IdentitySpec().ServiceAccountName + if diff := cmp.Diff(want, got); diff != "" { + t.Errorf("failed to get expected (-want, +got) = %v", diff) + } +} + +func TestCloudBuildSourceIdentityStatus(t *testing.T) { + s := &CloudBuildSource{ + Status: CloudBuildSourceStatus{ + PubSubStatus: v1.PubSubStatus{}, + }, + } + want := &v1.IdentityStatus{} + got := s.IdentityStatus() + if diff := cmp.Diff(want, got); diff != "" { + t.Errorf("failed to get expected (-want, +got) = %v", diff) + } +} + +func TestCloudBuildSourceConditionSet(t *testing.T) { + want := []apis.Condition{{ + Type: v1.PullSubscriptionReady, + }, { + Type: apis.ConditionReady, + }} + c := &CloudBuildSource{} + + c.ConditionSet().Manage(&c.Status).InitializeConditions() + var got []apis.Condition = c.Status.GetConditions() + + compareConditionTypes := cmp.Transformer("ConditionType", func(c apis.Condition) apis.ConditionType { + return c.Type + }) + sortConditionTypes := cmpopts.SortSlices(func(a, b apis.Condition) bool { + return a.Type < b.Type + }) + if diff := cmp.Diff(want, got, sortConditionTypes, compareConditionTypes); diff != "" { + t.Errorf("failed to get expected (-want, +got) = %v", diff) + } +} + +func TestCloudBuildSource_GetConditionSet(t *testing.T) { + s := &CloudBuildSource{} + + if got, want := s.GetConditionSet().GetTopLevelConditionType(), apis.ConditionReady; got != want { + t.Errorf("GetTopLevelCondition=%v, want=%v", got, want) + } +} + +func TestCloudBuildSource_GetStatus(t *testing.T) { + s := &CloudBuildSource{ + Status: CloudBuildSourceStatus{}, + } + if got, want := s.GetStatus(), &s.Status.Status; got != want { + t.Errorf("GetStatus=%v, want=%v", got, want) + } +} diff --git a/pkg/apis/events/v1/cloudbuildsource_validation.go b/pkg/apis/events/v1/cloudbuildsource_validation.go new file mode 100644 index 0000000000..2122498098 --- /dev/null +++ b/pkg/apis/events/v1/cloudbuildsource_validation.go @@ -0,0 +1,77 @@ +/* +Copyright 2020 Google LLC +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT 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 v1 + +import ( + "context" + + "k8s.io/apimachinery/pkg/api/equality" + "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + "github.com/google/knative-gcp/pkg/apis/duck" +) + +func (current *CloudBuildSource) Validate(ctx context.Context) *apis.FieldError { + errs := current.Spec.Validate(ctx).ViaField("spec") + + if apis.IsInUpdate(ctx) { + original := apis.GetBaseline(ctx).(*CloudBuildSource) + errs = errs.Also(current.CheckImmutableFields(ctx, original)) + } + + return duck.ValidateAutoscalingAnnotations(ctx, current.Annotations, errs) +} + +func (current *CloudBuildSourceSpec) Validate(ctx context.Context) *apis.FieldError { + var errs *apis.FieldError + + // Sink [required] + if equality.Semantic.DeepEqual(current.Sink, duckv1.Destination{}) { + errs = errs.Also(apis.ErrMissingField("sink")) + } else if err := current.Sink.Validate(ctx); err != nil { + errs = errs.Also(err.ViaField("sink")) + } + + if err := duck.ValidateCredential(current.Secret, current.ServiceAccountName); err != nil { + errs = errs.Also(err) + } + + return errs +} + +func (current *CloudBuildSource) CheckImmutableFields(ctx context.Context, original *CloudBuildSource) *apis.FieldError { + if original == nil { + return nil + } + + var errs *apis.FieldError + // Modification of Topic, Secret and Project are not allowed. Everything else is mutable. + if diff := cmp.Diff(original.Spec, current.Spec, + cmpopts.IgnoreFields(CloudBuildSourceSpec{}, + "Sink", "CloudEventOverrides")); diff != "" { + errs = errs.Also(&apis.FieldError{ + Message: "Immutable fields changed (-old +new)", + Paths: []string{"spec"}, + Details: diff, + }) + } + // Modification of AutoscalingClassAnnotations is not allowed. + errs = duck.CheckImmutableAutoscalingClassAnnotations(¤t.ObjectMeta, &original.ObjectMeta, errs) + + // Modification of non-empty cluster name annotation is not allowed. + return duck.CheckImmutableClusterNameAnnotation(¤t.ObjectMeta, &original.ObjectMeta, errs) +} diff --git a/pkg/apis/events/v1/cloudbuildsource_validation_test.go b/pkg/apis/events/v1/cloudbuildsource_validation_test.go new file mode 100644 index 0000000000..79db2c5583 --- /dev/null +++ b/pkg/apis/events/v1/cloudbuildsource_validation_test.go @@ -0,0 +1,488 @@ +/* +Copyright 2020 Google LLC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT 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 v1 + +import ( + "context" + "testing" + + gcpauthtesthelper "github.com/google/knative-gcp/pkg/apis/configs/gcpauth/testhelper" + + "github.com/google/knative-gcp/pkg/apis/duck" + gcpduckv1 "github.com/google/knative-gcp/pkg/apis/duck/v1" + metadatatesting "github.com/google/knative-gcp/pkg/gclient/metadata/testing" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + corev1 "k8s.io/api/core/v1" + "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" +) + +var ( + buildSourceSpec = CloudBuildSourceSpec{ + PubSubSpec: gcpduckv1.PubSubSpec{ + Secret: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: "secret-name", + }, + Key: "secret-key", + }, + SourceSpec: duckv1.SourceSpec{ + Sink: duckv1.Destination{ + Ref: &duckv1.KReference{ + APIVersion: "foo", + Kind: "bar", + Namespace: "baz", + Name: "qux", + }, + }, + }, + Project: "my-eventing-project", + }, + } + + buildSourceSpecWithKSA = CloudBuildSourceSpec{ + PubSubSpec: gcpduckv1.PubSubSpec{ + SourceSpec: duckv1.SourceSpec{ + Sink: duckv1.Destination{ + Ref: &duckv1.KReference{ + APIVersion: "foo", + Kind: "bar", + Namespace: "baz", + Name: "qux", + }, + }, + }, + IdentitySpec: gcpduckv1.IdentitySpec{ + ServiceAccountName: "old-service-account", + }, + Project: "my-eventing-project", + }, + } +) + +func TestCloudBuildSourceCheckValidationFields(t *testing.T) { + testCases := map[string]struct { + spec CloudBuildSourceSpec + error bool + }{ + "ok": { + spec: buildSourceSpec, + error: false, + }, + "bad sink, name": { + spec: func() CloudBuildSourceSpec { + obj := buildSourceSpec.DeepCopy() + obj.Sink.Ref.Name = "" + return *obj + }(), + error: true, + }, + "bad sink, apiVersion": { + spec: func() CloudBuildSourceSpec { + obj := buildSourceSpec.DeepCopy() + obj.Sink.Ref.APIVersion = "" + return *obj + }(), + error: true, + }, + "bad sink, kind": { + spec: func() CloudBuildSourceSpec { + obj := buildSourceSpec.DeepCopy() + obj.Sink.Ref.Kind = "" + return *obj + }(), + error: true, + }, + "bad sink, empty": { + spec: func() CloudBuildSourceSpec { + obj := buildSourceSpec.DeepCopy() + obj.Sink = duckv1.Destination{} + return *obj + }(), + error: true, + }, + "bad sink, uri scheme": { + spec: func() CloudBuildSourceSpec { + obj := buildSourceSpec.DeepCopy() + obj.Sink = duckv1.Destination{ + URI: &apis.URL{ + Host: "example.com", + }, + } + return *obj + }(), + error: true, + }, + "bad sink, uri host": { + spec: func() CloudBuildSourceSpec { + obj := buildSourceSpec.DeepCopy() + obj.Sink = duckv1.Destination{ + URI: &apis.URL{ + Scheme: "http", + }, + } + return *obj + }(), + error: true, + }, + "bad sink, uri and ref": { + spec: func() CloudBuildSourceSpec { + obj := buildSourceSpec.DeepCopy() + obj.Sink = duckv1.Destination{ + URI: &apis.URL{ + Scheme: "http", + Host: "example.com", + }, + Ref: &duckv1.KReference{ + Name: "foo", + }, + } + return *obj + }(), + error: true, + }, + "invalid secret, missing key": { + spec: func() CloudBuildSourceSpec { + obj := buildSourceSpec.DeepCopy() + obj.Secret = &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: "name", + }, + } + return *obj + }(), + error: true, + }, + "nil service account": { + spec: func() CloudBuildSourceSpec { + obj := buildSourceSpec.DeepCopy() + return *obj + }(), + error: false, + }, + "invalid k8s service account": { + spec: func() CloudBuildSourceSpec { + obj := buildSourceSpec.DeepCopy() + obj.ServiceAccountName = invalidServiceAccountName + return *obj + }(), + error: true, + }, + "have k8s service account and secret at the same time": { + spec: func() CloudBuildSourceSpec { + obj := buildSourceSpec.DeepCopy() + obj.ServiceAccountName = validServiceAccountName + obj.Secret = &gcpauthtesthelper.Secret + return *obj + }(), + error: true, + }, + } + for n, tc := range testCases { + t.Run(n, func(t *testing.T) { + err := tc.spec.Validate(context.TODO()) + if tc.error != (err != nil) { + t.Fatalf("Unexpected validation failure. Got %v", err) + } + }) + } +} + +func TestCloudBuildSourceCheckImmutableFields(t *testing.T) { + testCases := map[string]struct { + orig interface{} + updated CloudBuildSourceSpec + origAnnotation map[string]string + updatedAnnotation map[string]string + allowed bool + }{ + "nil orig": { + updated: buildSourceSpec, + allowed: true, + }, + "ClusterName annotation changed": { + origAnnotation: map[string]string{ + duck.ClusterNameAnnotation: metadatatesting.FakeClusterName + "old", + }, + updatedAnnotation: map[string]string{ + duck.ClusterNameAnnotation: metadatatesting.FakeClusterName + "new", + }, + allowed: false, + }, + "AnnotationClass annotation changed": { + origAnnotation: map[string]string{ + duck.AutoscalingClassAnnotation: duck.KEDA, + }, + updatedAnnotation: map[string]string{ + duck.AutoscalingClassAnnotation: duck.KEDA + "new", + }, + allowed: false, + }, + "AnnotationClass annotation added": { + origAnnotation: map[string]string{}, + updatedAnnotation: map[string]string{ + duck.AutoscalingClassAnnotation: duck.KEDA, + }, + allowed: false, + }, + "AnnotationClass annotation deleted": { + origAnnotation: map[string]string{ + duck.AutoscalingClassAnnotation: duck.KEDA, + }, + updatedAnnotation: map[string]string{}, + allowed: false, + }, + "Secret.Name changed": { + orig: &buildSourceSpec, + updated: CloudBuildSourceSpec{ + PubSubSpec: gcpduckv1.PubSubSpec{ + Secret: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: "some-other-name", + }, + Key: buildSourceSpec.Secret.Key, + }, + Project: buildSourceSpec.Project, + SourceSpec: duckv1.SourceSpec{ + Sink: buildSourceSpec.Sink, + }, + }, + }, + allowed: false, + }, + "Secret.Key changed": { + orig: &buildSourceSpec, + updated: CloudBuildSourceSpec{ + PubSubSpec: gcpduckv1.PubSubSpec{ + Secret: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: buildSourceSpec.Secret.Name, + }, + Key: "some-other-key", + }, + Project: buildSourceSpec.Project, + SourceSpec: duckv1.SourceSpec{ + Sink: buildSourceSpec.Sink, + }, + }, + }, + allowed: false, + }, + "Project changed": { + orig: &buildSourceSpec, + updated: CloudBuildSourceSpec{ + PubSubSpec: gcpduckv1.PubSubSpec{ + Secret: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: buildSourceSpec.Secret.Name, + }, + Key: buildSourceSpec.Secret.Key, + }, + Project: "some-other-project", + SourceSpec: duckv1.SourceSpec{ + Sink: buildSourceSpec.Sink, + }, + }, + }, + allowed: false, + }, + "ServiceAccountName changed": { + orig: &buildSourceSpecWithKSA, + updated: CloudBuildSourceSpec{ + PubSubSpec: gcpduckv1.PubSubSpec{ + IdentitySpec: gcpduckv1.IdentitySpec{ + ServiceAccountName: "new-service-account", + }, + SourceSpec: duckv1.SourceSpec{ + Sink: buildSourceSpecWithKSA.Sink, + }, + Project: buildSourceSpecWithKSA.Project, + }, + }, + allowed: false, + }, + "ServiceAccountName added": { + orig: &buildSourceSpec, + updated: CloudBuildSourceSpec{ + PubSubSpec: gcpduckv1.PubSubSpec{ + Secret: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: buildSourceSpec.Secret.Name, + }, + Key: buildSourceSpec.Secret.Key, + }, + Project: buildSourceSpec.Project, + SourceSpec: duckv1.SourceSpec{ + Sink: buildSourceSpec.Sink, + }, + IdentitySpec: gcpduckv1.IdentitySpec{ + ServiceAccountName: "old-service-account", + }, + }, + }, + allowed: false, + }, + "ClusterName annotation added": { + origAnnotation: nil, + updatedAnnotation: map[string]string{ + duck.ClusterNameAnnotation: metadatatesting.FakeClusterName + "new", + }, + allowed: true, + }, + "Sink.APIVersion changed": { + orig: &buildSourceSpec, + updated: CloudBuildSourceSpec{ + PubSubSpec: gcpduckv1.PubSubSpec{ + Secret: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: buildSourceSpec.Secret.Name, + }, + Key: buildSourceSpec.Secret.Key, + }, + Project: buildSourceSpec.Project, + SourceSpec: duckv1.SourceSpec{ + Sink: duckv1.Destination{ + Ref: &duckv1.KReference{ + APIVersion: "some-other-api-version", + Kind: buildSourceSpec.Sink.Ref.Kind, + Namespace: buildSourceSpec.Sink.Ref.Namespace, + Name: buildSourceSpec.Sink.Ref.Name, + }, + }, + }, + }, + }, + allowed: true, + }, + "Sink.Kind changed": { + orig: &buildSourceSpec, + updated: CloudBuildSourceSpec{ + PubSubSpec: gcpduckv1.PubSubSpec{ + Secret: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: buildSourceSpec.Secret.Name, + }, + Key: buildSourceSpec.Secret.Key, + }, + Project: buildSourceSpec.Project, + SourceSpec: duckv1.SourceSpec{ + Sink: duckv1.Destination{ + Ref: &duckv1.KReference{ + APIVersion: buildSourceSpec.Sink.Ref.APIVersion, + Kind: "some-other-kind", + Namespace: buildSourceSpec.Sink.Ref.Namespace, + Name: buildSourceSpec.Sink.Ref.Name, + }, + }, + }, + }, + }, + allowed: true, + }, + "Sink.Namespace changed": { + orig: &buildSourceSpec, + updated: CloudBuildSourceSpec{ + PubSubSpec: gcpduckv1.PubSubSpec{ + Secret: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: buildSourceSpec.Secret.Name, + }, + Key: buildSourceSpec.Secret.Key, + }, + Project: buildSourceSpec.Project, + SourceSpec: duckv1.SourceSpec{ + Sink: duckv1.Destination{ + Ref: &duckv1.KReference{ + APIVersion: buildSourceSpec.Sink.Ref.APIVersion, + Kind: buildSourceSpec.Sink.Ref.Kind, + Namespace: "some-other-namespace", + Name: buildSourceSpec.Sink.Ref.Name, + }, + }, + }, + }, + }, + allowed: true, + }, + "Sink.Name changed": { + orig: &buildSourceSpec, + updated: CloudBuildSourceSpec{ + PubSubSpec: gcpduckv1.PubSubSpec{ + Secret: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: buildSourceSpec.Secret.Name, + }, + Key: buildSourceSpec.Secret.Key, + }, + Project: buildSourceSpec.Project, + SourceSpec: duckv1.SourceSpec{ + Sink: duckv1.Destination{ + Ref: &duckv1.KReference{ + APIVersion: buildSourceSpec.Sink.Ref.APIVersion, + Kind: buildSourceSpec.Sink.Ref.Kind, + Namespace: buildSourceSpec.Sink.Ref.Namespace, + Name: "some-other-name", + }, + }, + }, + }, + }, + allowed: true, + }, + "no change": { + orig: &buildSourceSpec, + updated: buildSourceSpec, + allowed: true, + }, + "no spec": { + orig: []string{"wrong"}, + updated: buildSourceSpec, + allowed: true, + }, + } + + for n, tc := range testCases { + t.Run(n, func(t *testing.T) { + var orig *CloudBuildSource + + if tc.origAnnotation != nil { + orig = &CloudBuildSource{ + ObjectMeta: v1.ObjectMeta{ + Annotations: tc.origAnnotation, + }, + } + } else if tc.orig != nil { + if spec, ok := tc.orig.(*CloudBuildSourceSpec); ok { + orig = &CloudBuildSource{ + Spec: *spec, + } + } + } + updated := &CloudBuildSource{ + ObjectMeta: v1.ObjectMeta{ + Annotations: tc.updatedAnnotation, + }, + Spec: tc.updated, + } + err := updated.CheckImmutableFields(context.TODO(), orig) + if tc.allowed != (err == nil) { + t.Fatalf("Unexpected immutable field check. Expected %v. Actual %v", tc.allowed, err) + } + }) + } +} diff --git a/pkg/apis/events/v1/implements_test.go b/pkg/apis/events/v1/implements_test.go index 08694929df..3e67f615fd 100644 --- a/pkg/apis/events/v1/implements_test.go +++ b/pkg/apis/events/v1/implements_test.go @@ -19,8 +19,9 @@ package v1 import ( "testing" - "knative.dev/pkg/apis/duck" v1 "knative.dev/pkg/apis/duck/v1" + + "knative.dev/pkg/apis/duck" ) func TestTypesImplements(t *testing.T) { @@ -28,8 +29,16 @@ func TestTypesImplements(t *testing.T) { instance interface{} iface duck.Implementable }{ + {instance: &CloudAuditLogsSource{}, iface: &v1.Source{}}, + {instance: &CloudAuditLogsSource{}, iface: &v1.Conditions{}}, {instance: &CloudStorageSource{}, iface: &v1.Source{}}, {instance: &CloudStorageSource{}, iface: &v1.Conditions{}}, + {instance: &CloudSchedulerSource{}, iface: &v1.Source{}}, + {instance: &CloudSchedulerSource{}, iface: &v1.Conditions{}}, + {instance: &CloudPubSubSource{}, iface: &v1.Source{}}, + {instance: &CloudPubSubSource{}, iface: &v1.Conditions{}}, + {instance: &CloudBuildSource{}, iface: &v1.Source{}}, + {instance: &CloudBuildSource{}, iface: &v1.Conditions{}}, } for _, tc := range testCases { if err := duck.VerifyType(tc.instance, tc.iface); err != nil { diff --git a/pkg/apis/events/v1/register.go b/pkg/apis/events/v1/register.go index 9d9dc4fe21..ab67c66cc3 100644 --- a/pkg/apis/events/v1/register.go +++ b/pkg/apis/events/v1/register.go @@ -47,6 +47,8 @@ func addKnownTypes(scheme *runtime.Scheme) error { scheme.AddKnownTypes(SchemeGroupVersion, &CloudAuditLogsSource{}, &CloudAuditLogsSourceList{}, + &CloudBuildSource{}, + &CloudBuildSourceList{}, &CloudPubSubSource{}, &CloudPubSubSourceList{}, &CloudSchedulerSource{}, diff --git a/pkg/apis/events/v1/register_test.go b/pkg/apis/events/v1/register_test.go index 3c864fcb3b..2f0c361cfc 100644 --- a/pkg/apis/events/v1/register_test.go +++ b/pkg/apis/events/v1/register_test.go @@ -60,6 +60,7 @@ func TestKnownTypes(t *testing.T) { for _, name := range []string{ "CloudAuditLogsSource", + "CloudBuildSource", "CloudPubSubSource", "CloudSchedulerSource", "CloudStorageSource", diff --git a/pkg/apis/events/v1/zz_generated.deepcopy.go b/pkg/apis/events/v1/zz_generated.deepcopy.go index 44ece840a9..9755c73963 100644 --- a/pkg/apis/events/v1/zz_generated.deepcopy.go +++ b/pkg/apis/events/v1/zz_generated.deepcopy.go @@ -119,6 +119,101 @@ func (in *CloudAuditLogsSourceStatus) DeepCopy() *CloudAuditLogsSourceStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CloudBuildSource) DeepCopyInto(out *CloudBuildSource) { + *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 CloudBuildSource. +func (in *CloudBuildSource) DeepCopy() *CloudBuildSource { + if in == nil { + return nil + } + out := new(CloudBuildSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *CloudBuildSource) 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 *CloudBuildSourceList) DeepCopyInto(out *CloudBuildSourceList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]CloudBuildSource, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CloudBuildSourceList. +func (in *CloudBuildSourceList) DeepCopy() *CloudBuildSourceList { + if in == nil { + return nil + } + out := new(CloudBuildSourceList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *CloudBuildSourceList) 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 *CloudBuildSourceSpec) DeepCopyInto(out *CloudBuildSourceSpec) { + *out = *in + in.PubSubSpec.DeepCopyInto(&out.PubSubSpec) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CloudBuildSourceSpec. +func (in *CloudBuildSourceSpec) DeepCopy() *CloudBuildSourceSpec { + if in == nil { + return nil + } + out := new(CloudBuildSourceSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CloudBuildSourceStatus) DeepCopyInto(out *CloudBuildSourceStatus) { + *out = *in + in.PubSubStatus.DeepCopyInto(&out.PubSubStatus) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CloudBuildSourceStatus. +func (in *CloudBuildSourceStatus) DeepCopy() *CloudBuildSourceStatus { + if in == nil { + return nil + } + out := new(CloudBuildSourceStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CloudPubSubSource) DeepCopyInto(out *CloudPubSubSource) { *out = *in diff --git a/pkg/client/clientset/versioned/typed/events/v1/cloudbuildsource.go b/pkg/client/clientset/versioned/typed/events/v1/cloudbuildsource.go new file mode 100644 index 0000000000..e7cb4b01c2 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/events/v1/cloudbuildsource.go @@ -0,0 +1,191 @@ +/* +Copyright 2020 Google LLC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT 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 v1 + +import ( + "time" + + v1 "github.com/google/knative-gcp/pkg/apis/events/v1" + scheme "github.com/google/knative-gcp/pkg/client/clientset/versioned/scheme" + metav1 "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" +) + +// CloudBuildSourcesGetter has a method to return a CloudBuildSourceInterface. +// A group's client should implement this interface. +type CloudBuildSourcesGetter interface { + CloudBuildSources(namespace string) CloudBuildSourceInterface +} + +// CloudBuildSourceInterface has methods to work with CloudBuildSource resources. +type CloudBuildSourceInterface interface { + Create(*v1.CloudBuildSource) (*v1.CloudBuildSource, error) + Update(*v1.CloudBuildSource) (*v1.CloudBuildSource, error) + UpdateStatus(*v1.CloudBuildSource) (*v1.CloudBuildSource, error) + Delete(name string, options *metav1.DeleteOptions) error + DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error + Get(name string, options metav1.GetOptions) (*v1.CloudBuildSource, error) + List(opts metav1.ListOptions) (*v1.CloudBuildSourceList, error) + Watch(opts metav1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.CloudBuildSource, err error) + CloudBuildSourceExpansion +} + +// cloudBuildSources implements CloudBuildSourceInterface +type cloudBuildSources struct { + client rest.Interface + ns string +} + +// newCloudBuildSources returns a CloudBuildSources +func newCloudBuildSources(c *EventsV1Client, namespace string) *cloudBuildSources { + return &cloudBuildSources{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the cloudBuildSource, and returns the corresponding cloudBuildSource object, and an error if there is any. +func (c *cloudBuildSources) Get(name string, options metav1.GetOptions) (result *v1.CloudBuildSource, err error) { + result = &v1.CloudBuildSource{} + err = c.client.Get(). + Namespace(c.ns). + Resource("cloudbuildsources"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of CloudBuildSources that match those selectors. +func (c *cloudBuildSources) List(opts metav1.ListOptions) (result *v1.CloudBuildSourceList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1.CloudBuildSourceList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("cloudbuildsources"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested cloudBuildSources. +func (c *cloudBuildSources) Watch(opts metav1.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("cloudbuildsources"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch() +} + +// Create takes the representation of a cloudBuildSource and creates it. Returns the server's representation of the cloudBuildSource, and an error, if there is any. +func (c *cloudBuildSources) Create(cloudBuildSource *v1.CloudBuildSource) (result *v1.CloudBuildSource, err error) { + result = &v1.CloudBuildSource{} + err = c.client.Post(). + Namespace(c.ns). + Resource("cloudbuildsources"). + Body(cloudBuildSource). + Do(). + Into(result) + return +} + +// Update takes the representation of a cloudBuildSource and updates it. Returns the server's representation of the cloudBuildSource, and an error, if there is any. +func (c *cloudBuildSources) Update(cloudBuildSource *v1.CloudBuildSource) (result *v1.CloudBuildSource, err error) { + result = &v1.CloudBuildSource{} + err = c.client.Put(). + Namespace(c.ns). + Resource("cloudbuildsources"). + Name(cloudBuildSource.Name). + Body(cloudBuildSource). + 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 *cloudBuildSources) UpdateStatus(cloudBuildSource *v1.CloudBuildSource) (result *v1.CloudBuildSource, err error) { + result = &v1.CloudBuildSource{} + err = c.client.Put(). + Namespace(c.ns). + Resource("cloudbuildsources"). + Name(cloudBuildSource.Name). + SubResource("status"). + Body(cloudBuildSource). + Do(). + Into(result) + return +} + +// Delete takes name of the cloudBuildSource and deletes it. Returns an error if one occurs. +func (c *cloudBuildSources) Delete(name string, options *metav1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("cloudbuildsources"). + Name(name). + Body(options). + Do(). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *cloudBuildSources) DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.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("cloudbuildsources"). + VersionedParams(&listOptions, scheme.ParameterCodec). + Timeout(timeout). + Body(options). + Do(). + Error() +} + +// Patch applies the patch and returns the patched cloudBuildSource. +func (c *cloudBuildSources) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.CloudBuildSource, err error) { + result = &v1.CloudBuildSource{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("cloudbuildsources"). + SubResource(subresources...). + Name(name). + Body(data). + Do(). + Into(result) + return +} diff --git a/pkg/client/clientset/versioned/typed/events/v1/events_client.go b/pkg/client/clientset/versioned/typed/events/v1/events_client.go index 05a79ff431..fa7743a5c6 100644 --- a/pkg/client/clientset/versioned/typed/events/v1/events_client.go +++ b/pkg/client/clientset/versioned/typed/events/v1/events_client.go @@ -27,6 +27,7 @@ import ( type EventsV1Interface interface { RESTClient() rest.Interface CloudAuditLogsSourcesGetter + CloudBuildSourcesGetter CloudPubSubSourcesGetter CloudSchedulerSourcesGetter CloudStorageSourcesGetter @@ -41,6 +42,10 @@ func (c *EventsV1Client) CloudAuditLogsSources(namespace string) CloudAuditLogsS return newCloudAuditLogsSources(c, namespace) } +func (c *EventsV1Client) CloudBuildSources(namespace string) CloudBuildSourceInterface { + return newCloudBuildSources(c, namespace) +} + func (c *EventsV1Client) CloudPubSubSources(namespace string) CloudPubSubSourceInterface { return newCloudPubSubSources(c, namespace) } diff --git a/pkg/client/clientset/versioned/typed/events/v1/fake/fake_cloudbuildsource.go b/pkg/client/clientset/versioned/typed/events/v1/fake/fake_cloudbuildsource.go new file mode 100644 index 0000000000..a46397bbf5 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/events/v1/fake/fake_cloudbuildsource.go @@ -0,0 +1,140 @@ +/* +Copyright 2020 Google LLC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT 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 ( + eventsv1 "github.com/google/knative-gcp/pkg/apis/events/v1" + 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" +) + +// FakeCloudBuildSources implements CloudBuildSourceInterface +type FakeCloudBuildSources struct { + Fake *FakeEventsV1 + ns string +} + +var cloudbuildsourcesResource = schema.GroupVersionResource{Group: "events.cloud.google.com", Version: "v1", Resource: "cloudbuildsources"} + +var cloudbuildsourcesKind = schema.GroupVersionKind{Group: "events.cloud.google.com", Version: "v1", Kind: "CloudBuildSource"} + +// Get takes name of the cloudBuildSource, and returns the corresponding cloudBuildSource object, and an error if there is any. +func (c *FakeCloudBuildSources) Get(name string, options v1.GetOptions) (result *eventsv1.CloudBuildSource, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(cloudbuildsourcesResource, c.ns, name), &eventsv1.CloudBuildSource{}) + + if obj == nil { + return nil, err + } + return obj.(*eventsv1.CloudBuildSource), err +} + +// List takes label and field selectors, and returns the list of CloudBuildSources that match those selectors. +func (c *FakeCloudBuildSources) List(opts v1.ListOptions) (result *eventsv1.CloudBuildSourceList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(cloudbuildsourcesResource, cloudbuildsourcesKind, c.ns, opts), &eventsv1.CloudBuildSourceList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &eventsv1.CloudBuildSourceList{ListMeta: obj.(*eventsv1.CloudBuildSourceList).ListMeta} + for _, item := range obj.(*eventsv1.CloudBuildSourceList).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 cloudBuildSources. +func (c *FakeCloudBuildSources) Watch(opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(cloudbuildsourcesResource, c.ns, opts)) + +} + +// Create takes the representation of a cloudBuildSource and creates it. Returns the server's representation of the cloudBuildSource, and an error, if there is any. +func (c *FakeCloudBuildSources) Create(cloudBuildSource *eventsv1.CloudBuildSource) (result *eventsv1.CloudBuildSource, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(cloudbuildsourcesResource, c.ns, cloudBuildSource), &eventsv1.CloudBuildSource{}) + + if obj == nil { + return nil, err + } + return obj.(*eventsv1.CloudBuildSource), err +} + +// Update takes the representation of a cloudBuildSource and updates it. Returns the server's representation of the cloudBuildSource, and an error, if there is any. +func (c *FakeCloudBuildSources) Update(cloudBuildSource *eventsv1.CloudBuildSource) (result *eventsv1.CloudBuildSource, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(cloudbuildsourcesResource, c.ns, cloudBuildSource), &eventsv1.CloudBuildSource{}) + + if obj == nil { + return nil, err + } + return obj.(*eventsv1.CloudBuildSource), 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 *FakeCloudBuildSources) UpdateStatus(cloudBuildSource *eventsv1.CloudBuildSource) (*eventsv1.CloudBuildSource, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(cloudbuildsourcesResource, "status", c.ns, cloudBuildSource), &eventsv1.CloudBuildSource{}) + + if obj == nil { + return nil, err + } + return obj.(*eventsv1.CloudBuildSource), err +} + +// Delete takes name of the cloudBuildSource and deletes it. Returns an error if one occurs. +func (c *FakeCloudBuildSources) Delete(name string, options *v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteAction(cloudbuildsourcesResource, c.ns, name), &eventsv1.CloudBuildSource{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeCloudBuildSources) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(cloudbuildsourcesResource, c.ns, listOptions) + + _, err := c.Fake.Invokes(action, &eventsv1.CloudBuildSourceList{}) + return err +} + +// Patch applies the patch and returns the patched cloudBuildSource. +func (c *FakeCloudBuildSources) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *eventsv1.CloudBuildSource, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(cloudbuildsourcesResource, c.ns, name, pt, data, subresources...), &eventsv1.CloudBuildSource{}) + + if obj == nil { + return nil, err + } + return obj.(*eventsv1.CloudBuildSource), err +} diff --git a/pkg/client/clientset/versioned/typed/events/v1/fake/fake_events_client.go b/pkg/client/clientset/versioned/typed/events/v1/fake/fake_events_client.go index dff56601a8..8b9ce3cfe1 100644 --- a/pkg/client/clientset/versioned/typed/events/v1/fake/fake_events_client.go +++ b/pkg/client/clientset/versioned/typed/events/v1/fake/fake_events_client.go @@ -32,6 +32,10 @@ func (c *FakeEventsV1) CloudAuditLogsSources(namespace string) v1.CloudAuditLogs return &FakeCloudAuditLogsSources{c, namespace} } +func (c *FakeEventsV1) CloudBuildSources(namespace string) v1.CloudBuildSourceInterface { + return &FakeCloudBuildSources{c, namespace} +} + func (c *FakeEventsV1) CloudPubSubSources(namespace string) v1.CloudPubSubSourceInterface { return &FakeCloudPubSubSources{c, namespace} } diff --git a/pkg/client/clientset/versioned/typed/events/v1/generated_expansion.go b/pkg/client/clientset/versioned/typed/events/v1/generated_expansion.go index 0e40c9c8ad..6edb69d670 100644 --- a/pkg/client/clientset/versioned/typed/events/v1/generated_expansion.go +++ b/pkg/client/clientset/versioned/typed/events/v1/generated_expansion.go @@ -20,6 +20,8 @@ package v1 type CloudAuditLogsSourceExpansion interface{} +type CloudBuildSourceExpansion interface{} + type CloudPubSubSourceExpansion interface{} type CloudSchedulerSourceExpansion interface{} diff --git a/pkg/client/informers/externalversions/events/v1/cloudbuildsource.go b/pkg/client/informers/externalversions/events/v1/cloudbuildsource.go new file mode 100644 index 0000000000..1394d361fb --- /dev/null +++ b/pkg/client/informers/externalversions/events/v1/cloudbuildsource.go @@ -0,0 +1,89 @@ +/* +Copyright 2020 Google LLC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT 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 v1 + +import ( + time "time" + + eventsv1 "github.com/google/knative-gcp/pkg/apis/events/v1" + versioned "github.com/google/knative-gcp/pkg/client/clientset/versioned" + internalinterfaces "github.com/google/knative-gcp/pkg/client/informers/externalversions/internalinterfaces" + v1 "github.com/google/knative-gcp/pkg/client/listers/events/v1" + metav1 "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" +) + +// CloudBuildSourceInformer provides access to a shared informer and lister for +// CloudBuildSources. +type CloudBuildSourceInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1.CloudBuildSourceLister +} + +type cloudBuildSourceInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewCloudBuildSourceInformer constructs a new informer for CloudBuildSource 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 NewCloudBuildSourceInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredCloudBuildSourceInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredCloudBuildSourceInformer constructs a new informer for CloudBuildSource 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 NewFilteredCloudBuildSourceInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.EventsV1().CloudBuildSources(namespace).List(options) + }, + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.EventsV1().CloudBuildSources(namespace).Watch(options) + }, + }, + &eventsv1.CloudBuildSource{}, + resyncPeriod, + indexers, + ) +} + +func (f *cloudBuildSourceInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredCloudBuildSourceInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *cloudBuildSourceInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&eventsv1.CloudBuildSource{}, f.defaultInformer) +} + +func (f *cloudBuildSourceInformer) Lister() v1.CloudBuildSourceLister { + return v1.NewCloudBuildSourceLister(f.Informer().GetIndexer()) +} diff --git a/pkg/client/informers/externalversions/events/v1/interface.go b/pkg/client/informers/externalversions/events/v1/interface.go index 55941130a6..27bba6e2c4 100644 --- a/pkg/client/informers/externalversions/events/v1/interface.go +++ b/pkg/client/informers/externalversions/events/v1/interface.go @@ -26,6 +26,8 @@ import ( type Interface interface { // CloudAuditLogsSources returns a CloudAuditLogsSourceInformer. CloudAuditLogsSources() CloudAuditLogsSourceInformer + // CloudBuildSources returns a CloudBuildSourceInformer. + CloudBuildSources() CloudBuildSourceInformer // CloudPubSubSources returns a CloudPubSubSourceInformer. CloudPubSubSources() CloudPubSubSourceInformer // CloudSchedulerSources returns a CloudSchedulerSourceInformer. @@ -50,6 +52,11 @@ func (v *version) CloudAuditLogsSources() CloudAuditLogsSourceInformer { return &cloudAuditLogsSourceInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} } +// CloudBuildSources returns a CloudBuildSourceInformer. +func (v *version) CloudBuildSources() CloudBuildSourceInformer { + return &cloudBuildSourceInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} + // CloudPubSubSources returns a CloudPubSubSourceInformer. func (v *version) CloudPubSubSources() CloudPubSubSourceInformer { return &cloudPubSubSourceInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} diff --git a/pkg/client/informers/externalversions/generic.go b/pkg/client/informers/externalversions/generic.go index 7ce9984ef7..0bdf41786a 100644 --- a/pkg/client/informers/externalversions/generic.go +++ b/pkg/client/informers/externalversions/generic.go @@ -69,6 +69,8 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource // Group=events.cloud.google.com, Version=v1 case v1.SchemeGroupVersion.WithResource("cloudauditlogssources"): return &genericInformer{resource: resource.GroupResource(), informer: f.Events().V1().CloudAuditLogsSources().Informer()}, nil + case v1.SchemeGroupVersion.WithResource("cloudbuildsources"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Events().V1().CloudBuildSources().Informer()}, nil case v1.SchemeGroupVersion.WithResource("cloudpubsubsources"): return &genericInformer{resource: resource.GroupResource(), informer: f.Events().V1().CloudPubSubSources().Informer()}, nil case v1.SchemeGroupVersion.WithResource("cloudschedulersources"): diff --git a/pkg/client/injection/informers/events/v1/cloudbuildsource/cloudbuildsource.go b/pkg/client/injection/informers/events/v1/cloudbuildsource/cloudbuildsource.go new file mode 100644 index 0000000000..8754198cdd --- /dev/null +++ b/pkg/client/injection/informers/events/v1/cloudbuildsource/cloudbuildsource.go @@ -0,0 +1,52 @@ +/* +Copyright 2020 Google LLC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT 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 cloudbuildsource + +import ( + context "context" + + v1 "github.com/google/knative-gcp/pkg/client/informers/externalversions/events/v1" + factory "github.com/google/knative-gcp/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.Events().V1().CloudBuildSources() + return context.WithValue(ctx, Key{}, inf), inf.Informer() +} + +// Get extracts the typed informer from the context. +func Get(ctx context.Context) v1.CloudBuildSourceInformer { + untyped := ctx.Value(Key{}) + if untyped == nil { + logging.FromContext(ctx).Panic( + "Unable to fetch github.com/google/knative-gcp/pkg/client/informers/externalversions/events/v1.CloudBuildSourceInformer from context.") + } + return untyped.(v1.CloudBuildSourceInformer) +} diff --git a/pkg/client/injection/informers/events/v1/cloudbuildsource/fake/fake.go b/pkg/client/injection/informers/events/v1/cloudbuildsource/fake/fake.go new file mode 100644 index 0000000000..057c000bb4 --- /dev/null +++ b/pkg/client/injection/informers/events/v1/cloudbuildsource/fake/fake.go @@ -0,0 +1,40 @@ +/* +Copyright 2020 Google LLC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT 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" + + cloudbuildsource "github.com/google/knative-gcp/pkg/client/injection/informers/events/v1/cloudbuildsource" + fake "github.com/google/knative-gcp/pkg/client/injection/informers/factory/fake" + controller "knative.dev/pkg/controller" + injection "knative.dev/pkg/injection" +) + +var Get = cloudbuildsource.Get + +func init() { + injection.Fake.RegisterInformer(withInformer) +} + +func withInformer(ctx context.Context) (context.Context, controller.Informer) { + f := fake.Get(ctx) + inf := f.Events().V1().CloudBuildSources() + return context.WithValue(ctx, cloudbuildsource.Key{}, inf), inf.Informer() +} diff --git a/pkg/client/injection/reconciler/events/v1/cloudbuildsource/controller.go b/pkg/client/injection/reconciler/events/v1/cloudbuildsource/controller.go new file mode 100644 index 0000000000..6b8c936eb1 --- /dev/null +++ b/pkg/client/injection/reconciler/events/v1/cloudbuildsource/controller.go @@ -0,0 +1,142 @@ +/* +Copyright 2020 Google LLC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT 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 cloudbuildsource + +import ( + context "context" + fmt "fmt" + reflect "reflect" + strings "strings" + + versionedscheme "github.com/google/knative-gcp/pkg/client/clientset/versioned/scheme" + client "github.com/google/knative-gcp/pkg/client/injection/client" + cloudbuildsource "github.com/google/knative-gcp/pkg/client/injection/informers/events/v1/cloudbuildsource" + 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" + 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 = "cloudbuildsource-controller" + defaultFinalizerName = "cloudbuildsources.events.cloud.google.com" +) + +// 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)) + } + + cloudbuildsourceInformer := cloudbuildsource.Get(ctx) + + lister := cloudbuildsourceInformer.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/events/v1/cloudbuildsource/reconciler.go b/pkg/client/injection/reconciler/events/v1/cloudbuildsource/reconciler.go new file mode 100644 index 0000000000..c32f224196 --- /dev/null +++ b/pkg/client/injection/reconciler/events/v1/cloudbuildsource/reconciler.go @@ -0,0 +1,449 @@ +/* +Copyright 2020 Google LLC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT 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 cloudbuildsource + +import ( + context "context" + json "encoding/json" + fmt "fmt" + reflect "reflect" + + v1 "github.com/google/knative-gcp/pkg/apis/events/v1" + versioned "github.com/google/knative-gcp/pkg/client/clientset/versioned" + eventsv1 "github.com/google/knative-gcp/pkg/client/listers/events/v1" + zap "go.uber.org/zap" + corev1 "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" + record "k8s.io/client-go/tools/record" + controller "knative.dev/pkg/controller" + kmp "knative.dev/pkg/kmp" + logging "knative.dev/pkg/logging" + reconciler "knative.dev/pkg/reconciler" +) + +// Interface defines the strongly typed interfaces to be implemented by a +// controller reconciling v1.CloudBuildSource. +type Interface interface { + // ReconcileKind implements custom logic to reconcile v1.CloudBuildSource. 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 *v1.CloudBuildSource) reconciler.Event +} + +// Finalizer defines the strongly typed interfaces to be implemented by a +// controller finalizing v1.CloudBuildSource. +type Finalizer interface { + // FinalizeKind implements custom logic to finalize v1.CloudBuildSource. 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 *v1.CloudBuildSource) reconciler.Event +} + +// ReadOnlyInterface defines the strongly typed interfaces to be implemented by a +// controller reconciling v1.CloudBuildSource if they want to process resources for which +// they are not the leader. +type ReadOnlyInterface interface { + // ObserveKind implements logic to observe v1.CloudBuildSource. + // This method should not write to the API. + ObserveKind(ctx context.Context, o *v1.CloudBuildSource) reconciler.Event +} + +// ReadOnlyFinalizer defines the strongly typed interfaces to be implemented by a +// controller finalizing v1.CloudBuildSource 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 v1.CloudBuildSource. + // This method should not write to the API. + ObserveFinalizeKind(ctx context.Context, o *v1.CloudBuildSource) reconciler.Event +} + +type doReconcile func(ctx context.Context, o *v1.CloudBuildSource) reconciler.Event + +// reconcilerImpl implements controller.Reconciler for v1.CloudBuildSource 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 eventsv1.CloudBuildSourceLister + + // 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 eventsv1.CloudBuildSourceLister, 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) + + // Initialize the reconciler state. This will convert the namespace/name + // string into a distinct namespace and name, determin if this instance of + // the reconciler is the leader, and any additional interfaces implemented + // by the reconciler. Returns an error is the resource key is invalid. + s, err := newState(key, r) + if err != nil { + logger.Errorf("invalid resource key: %s", key) + return nil + } + + // If we are not the leader, and we don't implement either ReadOnly + // observer interfaces, then take a fast-path out. + if s.isNotLeaderNorObserver() { + 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.CloudBuildSources(s.namespace) + + original, err := getter.Get(s.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 + + name, do := s.reconcileMethodFor(resource) + // Append the target method to the logger. + logger = logger.With(zap.String("targetMethod", name)) + switch name { + case reconciler.DoReconcileKind: + // 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) + } + + if !r.skipStatusUpdates { + 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 = do(ctx, resource) + + if !r.skipStatusUpdates { + reconciler.PostProcessReconcile(ctx, resource, original) + } + + case reconciler.DoFinalizeKind: + // For finalizing reconcilers, if this resource being marked for deletion + // and reconciled cleanly (nil or normal event), remove the finalizer. + reconcileEvent = do(ctx, resource) + + if resource, err = r.clearFinalizer(ctx, resource, reconcileEvent); err != nil { + return fmt.Errorf("failed to clear finalizers: %w", err) + } + + case reconciler.DoObserveKind, reconciler.DoObserveFinalizeKind: + // Observe any changes to this resource, since we are not the leader. + reconcileEvent = do(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 !s.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(ctx, original, resource); err != nil { + logger.Warnw("Failed to update resource status", zap.Error(err)) + r.Recorder.Eventf(resource, corev1.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, corev1.EventTypeWarning, "InternalError", reconcileEvent.Error()) + return reconcileEvent + } + + return nil +} + +func (r *reconcilerImpl) updateStatus(ctx context.Context, existing *v1.CloudBuildSource, desired *v1.CloudBuildSource) 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.EventsV1().CloudBuildSources(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 + } + + if diff, err := kmp.SafeDiff(existing.Status, desired.Status); err == nil && diff != "" { + logging.FromContext(ctx).Debugf("Updating status with: %s", diff) + } + + existing.Status = desired.Status + + updater := r.Client.EventsV1().CloudBuildSources(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 *v1.CloudBuildSource) (*v1.CloudBuildSource, error) { + + getter := r.Lister.CloudBuildSources(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.EventsV1().CloudBuildSources(resource.Namespace) + + resourceName := resource.Name + resource, err = patcher.Patch(resourceName, types.MergePatchType, patch) + if err != nil { + r.Recorder.Eventf(resource, corev1.EventTypeWarning, "FinalizerUpdateFailed", + "Failed to update finalizers for %q: %v", resourceName, err) + } else { + r.Recorder.Eventf(resource, corev1.EventTypeNormal, "FinalizerUpdate", + "Updated %q finalizers", resource.GetName()) + } + return resource, err +} + +func (r *reconcilerImpl) setFinalizerIfFinalizer(ctx context.Context, resource *v1.CloudBuildSource) (*v1.CloudBuildSource, 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 *v1.CloudBuildSource, reconcileEvent reconciler.Event) (*v1.CloudBuildSource, 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 == corev1.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/events/v1/cloudbuildsource/state.go b/pkg/client/injection/reconciler/events/v1/cloudbuildsource/state.go new file mode 100644 index 0000000000..95e6440908 --- /dev/null +++ b/pkg/client/injection/reconciler/events/v1/cloudbuildsource/state.go @@ -0,0 +1,106 @@ +/* +Copyright 2020 Google LLC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT 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 cloudbuildsource + +import ( + fmt "fmt" + + v1 "github.com/google/knative-gcp/pkg/apis/events/v1" + types "k8s.io/apimachinery/pkg/types" + cache "k8s.io/client-go/tools/cache" + reconciler "knative.dev/pkg/reconciler" +) + +// state is used to track the state of a reconciler in a single run. +type state struct { + // Key is the original reconciliation key from the queue. + key string + // Namespace is the namespace split from the reconciliation key. + namespace string + // Namespace is the name split from the reconciliation key. + name string + // reconciler is the reconciler. + reconciler Interface + // rof is the read only interface cast of the reconciler. + roi ReadOnlyInterface + // IsROI (Read Only Interface) the reconciler only observes reconciliation. + isROI bool + // rof is the read only finalizer cast of the reconciler. + rof ReadOnlyFinalizer + // IsROF (Read Only Finalizer) the reconciler only observes finalize. + isROF bool + // IsLeader the instance of the reconciler is the elected leader. + isLeader bool +} + +func newState(key string, r *reconcilerImpl) (*state, error) { + // Convert the namespace/name string into a distinct namespace and name + namespace, name, err := cache.SplitMetaNamespaceKey(key) + if err != nil { + return nil, fmt.Errorf("invalid resource key: %s", key) + } + + roi, isROI := r.reconciler.(ReadOnlyInterface) + rof, isROF := r.reconciler.(ReadOnlyFinalizer) + + isLeader := r.IsLeaderFor(types.NamespacedName{ + Namespace: namespace, + Name: name, + }) + + return &state{ + key: key, + namespace: namespace, + name: name, + reconciler: r.reconciler, + roi: roi, + isROI: isROI, + rof: rof, + isROF: isROF, + isLeader: isLeader, + }, nil +} + +// isNotLeaderNorObserver checks to see if this reconciler with the current +// state is enabled to do any work or not. +// isNotLeaderNorObserver returns true when there is no work possible for the +// reconciler. +func (s *state) isNotLeaderNorObserver() bool { + if !s.isLeader && !s.isROI && !s.isROF { + // If we are not the leader, and we don't implement either ReadOnly + // interface, then take a fast-path out. + return true + } + return false +} + +func (s *state) reconcileMethodFor(o *v1.CloudBuildSource) (string, doReconcile) { + if o.GetDeletionTimestamp().IsZero() { + if s.isLeader { + return reconciler.DoReconcileKind, s.reconciler.ReconcileKind + } else if s.isROI { + return reconciler.DoObserveKind, s.roi.ObserveKind + } + } else if fin, ok := s.reconciler.(Finalizer); s.isLeader && ok { + return reconciler.DoFinalizeKind, fin.FinalizeKind + } else if !s.isLeader && s.isROF { + return reconciler.DoObserveFinalizeKind, s.rof.ObserveFinalizeKind + } + return "unknown", nil +} diff --git a/pkg/client/listers/events/v1/cloudbuildsource.go b/pkg/client/listers/events/v1/cloudbuildsource.go new file mode 100644 index 0000000000..65fc7d16be --- /dev/null +++ b/pkg/client/listers/events/v1/cloudbuildsource.go @@ -0,0 +1,94 @@ +/* +Copyright 2020 Google LLC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT 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 v1 + +import ( + v1 "github.com/google/knative-gcp/pkg/apis/events/v1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" +) + +// CloudBuildSourceLister helps list CloudBuildSources. +type CloudBuildSourceLister interface { + // List lists all CloudBuildSources in the indexer. + List(selector labels.Selector) (ret []*v1.CloudBuildSource, err error) + // CloudBuildSources returns an object that can list and get CloudBuildSources. + CloudBuildSources(namespace string) CloudBuildSourceNamespaceLister + CloudBuildSourceListerExpansion +} + +// cloudBuildSourceLister implements the CloudBuildSourceLister interface. +type cloudBuildSourceLister struct { + indexer cache.Indexer +} + +// NewCloudBuildSourceLister returns a new CloudBuildSourceLister. +func NewCloudBuildSourceLister(indexer cache.Indexer) CloudBuildSourceLister { + return &cloudBuildSourceLister{indexer: indexer} +} + +// List lists all CloudBuildSources in the indexer. +func (s *cloudBuildSourceLister) List(selector labels.Selector) (ret []*v1.CloudBuildSource, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1.CloudBuildSource)) + }) + return ret, err +} + +// CloudBuildSources returns an object that can list and get CloudBuildSources. +func (s *cloudBuildSourceLister) CloudBuildSources(namespace string) CloudBuildSourceNamespaceLister { + return cloudBuildSourceNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// CloudBuildSourceNamespaceLister helps list and get CloudBuildSources. +type CloudBuildSourceNamespaceLister interface { + // List lists all CloudBuildSources in the indexer for a given namespace. + List(selector labels.Selector) (ret []*v1.CloudBuildSource, err error) + // Get retrieves the CloudBuildSource from the indexer for a given namespace and name. + Get(name string) (*v1.CloudBuildSource, error) + CloudBuildSourceNamespaceListerExpansion +} + +// cloudBuildSourceNamespaceLister implements the CloudBuildSourceNamespaceLister +// interface. +type cloudBuildSourceNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all CloudBuildSources in the indexer for a given namespace. +func (s cloudBuildSourceNamespaceLister) List(selector labels.Selector) (ret []*v1.CloudBuildSource, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1.CloudBuildSource)) + }) + return ret, err +} + +// Get retrieves the CloudBuildSource from the indexer for a given namespace and name. +func (s cloudBuildSourceNamespaceLister) Get(name string) (*v1.CloudBuildSource, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1.Resource("cloudbuildsource"), name) + } + return obj.(*v1.CloudBuildSource), nil +} diff --git a/pkg/client/listers/events/v1/expansion_generated.go b/pkg/client/listers/events/v1/expansion_generated.go index 8ddddc854f..31cc8d662c 100644 --- a/pkg/client/listers/events/v1/expansion_generated.go +++ b/pkg/client/listers/events/v1/expansion_generated.go @@ -26,6 +26,14 @@ type CloudAuditLogsSourceListerExpansion interface{} // CloudAuditLogsSourceNamespaceLister. type CloudAuditLogsSourceNamespaceListerExpansion interface{} +// CloudBuildSourceListerExpansion allows custom methods to be added to +// CloudBuildSourceLister. +type CloudBuildSourceListerExpansion interface{} + +// CloudBuildSourceNamespaceListerExpansion allows custom methods to be added to +// CloudBuildSourceNamespaceLister. +type CloudBuildSourceNamespaceListerExpansion interface{} + // CloudPubSubSourceListerExpansion allows custom methods to be added to // CloudPubSubSourceLister. type CloudPubSubSourceListerExpansion interface{}