diff --git a/charts/fleet/templates/rbac_gitjob.yaml b/charts/fleet/templates/rbac_gitjob.yaml index a182c798d9..dba8b13cfc 100644 --- a/charts/fleet/templates/rbac_gitjob.yaml +++ b/charts/fleet/templates/rbac_gitjob.yaml @@ -61,7 +61,7 @@ rules: - watch - update - apiGroups: - - "" + - "events.k8s.io" resources: - 'events' verbs: diff --git a/e2e/single-cluster/gitrepo_test.go b/e2e/single-cluster/gitrepo_test.go index aefbd50a5b..b45e8aa5e6 100644 --- a/e2e/single-cluster/gitrepo_test.go +++ b/e2e/single-cluster/gitrepo_test.go @@ -151,6 +151,12 @@ var _ = Describe("Monitoring Git repos via HTTP for change", Label("infra-setup" out, _ := k.Namespace(targetNamespace).Get("deployments") return out }, testenv.MediumTimeout, testenv.ShortTimeout).Should(ContainSubstring("newsleep")) + + By("checking that events are generated") + Eventually(func() string { + out, _ := k.Get("events", "--field-selector=reason=GotNewCommit") + return out + }).Should(ContainSubstring(commit)) }) }) diff --git a/integrationtests/gitjob/controller/controller_test.go b/integrationtests/gitjob/controller/controller_test.go index e62a4c0da9..8964b90115 100644 --- a/integrationtests/gitjob/controller/controller_test.go +++ b/integrationtests/gitjob/controller/controller_test.go @@ -438,15 +438,15 @@ var _ = Describe("GitJob controller", func() { g.Expect(events.Items[0].Reason).To(Equal("GotNewCommit")) g.Expect(events.Items[0].Message).To(Equal("9ca3a0ad308ed8bffa6602572e2a1343af9c3d2e")) g.Expect(events.Items[0].Type).To(Equal("Normal")) - g.Expect(events.Items[0].Source.Component).To(Equal("gitjob-controller")) + g.Expect(events.Items[0].ReportingController).To(Equal("gitjob-controller")) g.Expect(events.Items[1].Reason).To(Equal("Created")) g.Expect(events.Items[1].Message).To(Equal("GitJob was created")) + g.Expect(events.Items[1].ReportingController).To(Equal("gitjob-controller")) g.Expect(events.Items[1].Type).To(Equal("Normal")) - g.Expect(events.Items[1].Source.Component).To(Equal("gitjob-controller")) g.Expect(events.Items[2].Reason).To(Equal("JobDeleted")) g.Expect(events.Items[2].Message).To(Equal("job deletion triggered because job succeeded")) g.Expect(events.Items[2].Type).To(Equal("Normal")) - g.Expect(events.Items[2].Source.Component).To(Equal("gitjob-controller")) + g.Expect(events.Items[2].ReportingController).To(Equal("gitjob-controller")) }).Should(Succeed()) // job should not be present @@ -706,10 +706,12 @@ var _ = Describe("GitJob controller", func() { return string(job.UID) != string(newJob.UID) }).Should(BeTrue()) - // it should log 3 events + // it should log 5 events: // first one is to log the new commit from the poller // second one is to inform that the job was created // third one reports on the job being deleted because of ForceUpdateGeneration + // the fourth and fifth ones represent job re-creation and deletion after successful completion, + // respectively Eventually(func(g Gomega) { events, _ := k8sClientSet.CoreV1().Events(gitRepo.Namespace).List(context.TODO(), metav1.ListOptions{ @@ -717,19 +719,27 @@ var _ = Describe("GitJob controller", func() { TypeMeta: metav1.TypeMeta{Kind: "GitRepo"}, }) g.Expect(events).ToNot(BeNil()) - g.Expect(events.Items).To(HaveLen(3)) + g.Expect(events.Items).To(HaveLen(5)) + + for _, e := range events.Items { + g.Expect(e.ReportingController).To(Equal("gitjob-controller")) + g.Expect(e.Type).To(Equal("Normal")) + } + g.Expect(events.Items[0].Reason).To(Equal("GotNewCommit")) g.Expect(events.Items[0].Message).To(Equal("9ca3a0ad308ed8bffa6602572e2a1343af9c3d2e")) - g.Expect(events.Items[0].Type).To(Equal("Normal")) - g.Expect(events.Items[0].Source.Component).To(Equal("gitjob-controller")) + g.Expect(events.Items[1].Reason).To(Equal("Created")) g.Expect(events.Items[1].Message).To(Equal("GitJob was created")) - g.Expect(events.Items[1].Type).To(Equal("Normal")) - g.Expect(events.Items[1].Source.Component).To(Equal("gitjob-controller")) + g.Expect(events.Items[2].Reason).To(Equal("JobDeleted")) g.Expect(events.Items[2].Message).To(Equal("job deletion triggered because job succeeded")) - g.Expect(events.Items[2].Type).To(Equal("Normal")) - g.Expect(events.Items[2].Source.Component).To(Equal("gitjob-controller")) + + g.Expect(events.Items[3].Reason).To(Equal("Created")) + g.Expect(events.Items[3].Message).To(Equal("GitJob was created")) + + g.Expect(events.Items[4].Reason).To(Equal("JobDeleted")) + g.Expect(events.Items[4].Message).To(Equal("job deletion triggered because job succeeded")) }).Should(Succeed()) }) diff --git a/integrationtests/gitjob/controller/suite_test.go b/integrationtests/gitjob/controller/suite_test.go index be5c6c2339..06674e5d8c 100644 --- a/integrationtests/gitjob/controller/suite_test.go +++ b/integrationtests/gitjob/controller/suite_test.go @@ -166,7 +166,7 @@ var _ = BeforeSuite(func() { Scheduler: sched, GitFetcher: fetcherMock, Clock: reconciler.RealClock{}, - Recorder: mgr.GetEventRecorderFor("gitjob-controller"), + Recorder: mgr.GetEventRecorder("gitjob-controller"), Workers: 50, SystemNamespace: "default", KnownHosts: ssh.KnownHosts{}, diff --git a/integrationtests/helmops/controller/suite_test.go b/integrationtests/helmops/controller/suite_test.go index 1c7f77c545..4e7ef848d0 100644 --- a/integrationtests/helmops/controller/suite_test.go +++ b/integrationtests/helmops/controller/suite_test.go @@ -88,7 +88,7 @@ var _ = BeforeSuite(func() { err = (&reconciler.HelmOpReconciler{ Client: mgr.GetClient(), Scheme: mgr.GetScheme(), - Recorder: mgr.GetEventRecorderFor("helmops-controller"), + Recorder: mgr.GetEventRecorder("helmops-controller"), Scheduler: sched, Workers: 50, }).SetupWithManager(mgr) diff --git a/internal/cmd/controller/gitops/operator.go b/internal/cmd/controller/gitops/operator.go index 632156b4ce..691659519d 100644 --- a/internal/cmd/controller/gitops/operator.go +++ b/internal/cmd/controller/gitops/operator.go @@ -186,7 +186,7 @@ func (g *GitOperator) Run(cmd *cobra.Command, args []string) error { JobNodeSelector: g.ShardNodeSelector, GitFetcher: &git.Fetch{KnownHosts: kh}, Clock: reconciler.RealClock{}, - Recorder: mgr.GetEventRecorderFor(fmt.Sprintf("fleet-gitops%s", shardIDSuffix)), + Recorder: mgr.GetEventRecorder(fmt.Sprintf("fleet-gitops%s", shardIDSuffix)), SystemNamespace: namespace, KnownHosts: kh, WithImagescan: imagescanEnabled, diff --git a/internal/cmd/controller/gitops/reconciler/gitjob.go b/internal/cmd/controller/gitops/reconciler/gitjob.go index 45ea912b5f..a6ef56bf78 100644 --- a/internal/cmd/controller/gitops/reconciler/gitjob.go +++ b/internal/cmd/controller/gitops/reconciler/gitjob.go @@ -19,7 +19,6 @@ import ( ssh "github.com/rancher/fleet/internal/ssh" v1alpha1 "github.com/rancher/fleet/pkg/apis/fleet.cattle.io/v1alpha1" "github.com/rancher/fleet/pkg/cert" - fleetevent "github.com/rancher/fleet/pkg/event" "github.com/rancher/fleet/pkg/sharding" appsv1 "k8s.io/api/apps/v1" @@ -70,7 +69,14 @@ func (r *GitJobReconciler) createJobAndResources(ctx context.Context, gitrepo *v return fmt.Errorf("error creating git job: %w", err) } - r.Recorder.Event(gitrepo, fleetevent.Normal, "Created", "GitJob was created") + r.Recorder.Eventf( + gitrepo, + nil, + corev1.EventTypeNormal, + "Created", + "CreateGitJob", + "GitJob was created", + ) return nil } diff --git a/internal/cmd/controller/gitops/reconciler/gitjob_controller.go b/internal/cmd/controller/gitops/reconciler/gitjob_controller.go index 7e39e54970..942eb3eb80 100644 --- a/internal/cmd/controller/gitops/reconciler/gitjob_controller.go +++ b/internal/cmd/controller/gitops/reconciler/gitjob_controller.go @@ -24,7 +24,6 @@ import ( "github.com/rancher/fleet/internal/metrics" v1alpha1 "github.com/rancher/fleet/pkg/apis/fleet.cattle.io/v1alpha1" "github.com/rancher/fleet/pkg/durations" - fleetevent "github.com/rancher/fleet/pkg/event" "github.com/rancher/fleet/pkg/sharding" "github.com/rancher/wrangler/v3/pkg/condition" @@ -41,7 +40,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" errutil "k8s.io/apimachinery/pkg/util/errors" - "k8s.io/client-go/tools/record" + "k8s.io/client-go/tools/events" "k8s.io/client-go/util/retry" "sigs.k8s.io/cli-utils/pkg/kstatus/status" ctrl "sigs.k8s.io/controller-runtime" @@ -141,7 +140,7 @@ type GitJobReconciler struct { JobNodeSelector string GitFetcher GitFetcher Clock TimeGetter - Recorder record.EventRecorder + Recorder events.EventRecorder SystemNamespace string KnownHosts KnownHostsGetter WithImagescan bool @@ -202,7 +201,16 @@ func (r *GitJobReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctr // Restrictions / Overrides, gitrepo reconciler is responsible for setting error in status oldStatus := gitrepo.Status.DeepCopy() if err := AuthorizeAndAssignDefaults(ctx, r.Client, gitrepo); err != nil { - r.Recorder.Event(gitrepo, fleetevent.Warning, "FailedToApplyRestrictions", err.Error()) + r.Recorder.Eventf( + gitrepo, + nil, + corev1.EventTypeWarning, + "FailedToApplyRestrictions", + "ApplyGitRepoRestrictions", + "%v", + err, + ) + return ctrl.Result{}, updateErrorStatus(ctx, r.Client, req.NamespacedName, *oldStatus, err) } @@ -306,7 +314,15 @@ func (r *GitJobReconciler) manageGitJob(ctx context.Context, logger logr.Logger, }, &job) if err != nil && !apierrors.IsNotFound(err) { err = fmt.Errorf("error retrieving git job: %w", err) - r.Recorder.Event(gitrepo, fleetevent.Warning, "FailedToGetGitJob", err.Error()) + r.Recorder.Eventf( + gitrepo, + nil, + corev1.EventTypeWarning, + "FailedToGetGitJob", + "GetGitJob", + "%v", + err, + ) return ctrl.Result{}, err } @@ -314,7 +330,15 @@ func (r *GitJobReconciler) manageGitJob(ctx context.Context, logger logr.Logger, if apierrors.IsNotFound(err) { clientSecretChanged, helmSecretChanged, err := r.hasReferencedSecretChanged(ctx, gitrepo) if err != nil { - r.Recorder.Event(gitrepo, fleetevent.Warning, "FailedValidatingSecret", err.Error()) + r.Recorder.Eventf( + gitrepo, + nil, + corev1.EventTypeWarning, + "FailedValidatingSecret", + "ValidateSecret", + "%v", + err, + ) return ctrl.Result{}, fmt.Errorf("error validating external secrets: %w", err) } @@ -333,16 +357,39 @@ func (r *GitJobReconciler) manageGitJob(ctx context.Context, logger logr.Logger, gitrepo.Status.Commit = commit } if err != nil { - r.Recorder.Event(gitrepo, fleetevent.Warning, "Failed", err.Error()) + r.Recorder.Eventf( + gitrepo, + nil, + corev1.EventTypeWarning, + "Failed", + "MonitorLatestCommit", + "%v", + err, + ) } else if oldCommit != gitrepo.Status.Commit { - r.Recorder.Event(gitrepo, fleetevent.Normal, "GotNewCommit", gitrepo.Status.Commit) + r.Recorder.Eventf( + gitrepo, + nil, + corev1.EventTypeNormal, + "GotNewCommit", + "GetNewCommit", + gitrepo.Status.Commit, + ) } } if r.shouldCreateJob(gitrepo, oldCommit, helmSecretChanged) { r.updateGenerationValuesIfNeeded(gitrepo) if err := r.validateExternalSecretExist(ctx, gitrepo); err != nil { - r.Recorder.Event(gitrepo, fleetevent.Warning, "FailedValidatingSecret", err.Error()) + r.Recorder.Eventf( + gitrepo, + nil, + corev1.EventTypeWarning, + "FailedValidatingSecret", + "ValidateSecret", + "%v", + err, + ) return ctrl.Result{}, fmt.Errorf("error validating external secrets: %w", err) } if err := r.createJobAndResources(ctx, gitrepo, logger); err != nil { @@ -581,7 +628,14 @@ func (r *GitJobReconciler) deleteJobIfNeeded(ctx context.Context, gitRepo *v1alp if err := r.Delete(ctx, job, client.PropagationPolicy(metav1.DeletePropagationBackground)); err != nil && !apierrors.IsNotFound(err) { return err, false } - r.Recorder.Event(gitRepo, fleetevent.Normal, "JobDeleted", jobDeletedMessage) + r.Recorder.Eventf( + gitRepo, + nil, + corev1.EventTypeNormal, + "JobDeleted", + "DeleteJob", + jobDeletedMessage, + ) } // finally if there's a job and any of the secrets related to the gitrepo changed, diff --git a/internal/cmd/controller/gitops/reconciler/gitjob_test.go b/internal/cmd/controller/gitops/reconciler/gitjob_test.go index 6f52089747..9356712b17 100644 --- a/internal/cmd/controller/gitops/reconciler/gitjob_test.go +++ b/internal/cmd/controller/gitops/reconciler/gitjob_test.go @@ -1,4 +1,5 @@ //go:generate mockgen --build_flags=--mod=mod -destination=../../../../mocks/client_mock.go -package=mocks -mock_names=Client=MockK8sClient,SubResourceWriter=MockStatusWriter sigs.k8s.io/controller-runtime/pkg/client Client,SubResourceWriter +//go:generate mockgen --build_flags=--mod=mod -destination=../../../../mocks/eventrecorder_mock.go -package=mocks k8s.io/client-go/tools/events EventRecorder package reconciler @@ -22,7 +23,6 @@ import ( "github.com/rancher/wrangler/v3/pkg/genericcondition" "go.uber.org/mock/gomock" - fleetevent "github.com/rancher/fleet/pkg/event" appsv1 "k8s.io/api/apps/v1" batchv1 "k8s.io/api/batch/v1" corev1 "k8s.io/api/core/v1" @@ -85,6 +85,24 @@ func (m gitRepoPointerMatcher) String() string { return "" } +// errorMatcher implements a gomock matcher on error message strings. +type errorMatcher struct { + errMsg string +} + +func (m errorMatcher) Matches(x interface{}) bool { + err, ok := x.(error) + if !ok { + return false + } + + return err.Error() == m.errMsg +} + +func (m errorMatcher) String() string { + return fmt.Sprintf("matches error %q", m.errMsg) +} + func TestReconcile_Error_WhenGitrepoRestrictionsAreNotMet(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() @@ -129,11 +147,14 @@ func TestReconcile_Error_WhenGitrepoRestrictionsAreNotMet(t *testing.T) { ) recorderMock := mocks.NewMockEventRecorder(mockCtrl) - recorderMock.EXPECT().Event( + recorderMock.EXPECT().Eventf( &gitRepoMatcher{gitRepo}, - fleetevent.Warning, + nil, + corev1.EventTypeWarning, "FailedToApplyRestrictions", - "empty targetNamespace denied, because allowedTargetNamespaces restriction is present", + "ApplyGitRepoRestrictions", + "%v", + errorMatcher{"empty targetNamespace denied, because allowedTargetNamespaces restriction is present"}, ) r := GitJobReconciler{ @@ -204,11 +225,14 @@ func TestReconcile_Error_WhenGetGitJobErrors(t *testing.T) { recorderMock := mocks.NewMockEventRecorder(mockCtrl) - recorderMock.EXPECT().Event( + recorderMock.EXPECT().Eventf( &gitRepoMatcher{gitRepo}, - fleetevent.Warning, + nil, + corev1.EventTypeWarning, "FailedToGetGitJob", - "error retrieving git job: GITJOB ERROR", + "GetGitJob", + "%v", + errorMatcher{"error retrieving git job: GITJOB ERROR"}, ) r := GitJobReconciler{ @@ -275,11 +299,14 @@ func TestReconcile_Error_WhenSecretDoesNotExist(t *testing.T) { recorderMock := mocks.NewMockEventRecorder(mockCtrl) - recorderMock.EXPECT().Event( + recorderMock.EXPECT().Eventf( &gitRepoMatcher{gitRepo}, - fleetevent.Warning, + nil, + corev1.EventTypeWarning, "FailedValidatingSecret", - "failed to look up HelmSecretNameForPaths, error: SECRET ERROR", + "ValidateSecret", + "%v", + errorMatcher{"failed to look up HelmSecretNameForPaths, error: SECRET ERROR"}, ) statusClient := mocks.NewMockStatusWriter(mockCtrl) diff --git a/internal/cmd/controller/gitops/reconciler/polling_job.go b/internal/cmd/controller/gitops/reconciler/polling_job.go index f98982ea6b..121fe4293f 100644 --- a/internal/cmd/controller/gitops/reconciler/polling_job.go +++ b/internal/cmd/controller/gitops/reconciler/polling_job.go @@ -11,15 +11,15 @@ import ( "golang.org/x/sync/semaphore" fleet "github.com/rancher/fleet/pkg/apis/fleet.cattle.io/v1alpha1" - fleetevent "github.com/rancher/fleet/pkg/event" "github.com/rancher/wrangler/v3/pkg/condition" "github.com/rancher/wrangler/v3/pkg/kstatus" + corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" errutil "k8s.io/apimachinery/pkg/util/errors" - "k8s.io/client-go/tools/record" + "k8s.io/client-go/tools/events" "k8s.io/client-go/util/retry" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/log" @@ -37,11 +37,11 @@ type gitPollingJob struct { repo string branch string - recorder record.EventRecorder + recorder events.EventRecorder gitFetcher GitFetcher } -func newGitPollingJob(c client.Client, r record.EventRecorder, repo fleet.GitRepo, fetcher GitFetcher) *gitPollingJob { +func newGitPollingJob(c client.Client, r events.EventRecorder, repo fleet.GitRepo, fetcher GitFetcher) *gitPollingJob { return &gitPollingJob{ sem: semaphore.NewWeighted(1), client: c, @@ -89,7 +89,16 @@ func (j *gitPollingJob) pollGitRepo(ctx context.Context) error { pollingTimestamp := time.Now().UTC() fail := func(origErr error) error { - j.recorder.Event(gitrepo, fleetevent.Warning, "FailedToCheckCommit", origErr.Error()) + j.recorder.Eventf( + gitrepo, + nil, + corev1.EventTypeWarning, + "FailedToCheckCommit", + "CheckCommit", + "%v", + origErr, + ) + return j.updateErrorStatus(ctx, gitrepo, pollingTimestamp, origErr) } @@ -101,7 +110,14 @@ func (j *gitPollingJob) pollGitRepo(ctx context.Context) error { } if commit != gitrepo.Status.Commit { - j.recorder.Event(gitrepo, fleetevent.Normal, "GotNewCommit", commit) + j.recorder.Eventf( + gitrepo, + nil, + corev1.EventTypeNormal, + "GotNewCommit", + "GetNewCommit", + commit, + ) } err = retry.RetryOnConflict(retry.DefaultRetry, func() error { diff --git a/internal/cmd/controller/gitops/reconciler/polling_job_test.go b/internal/cmd/controller/gitops/reconciler/polling_job_test.go index e27adae8f8..4f312cfd2f 100644 --- a/internal/cmd/controller/gitops/reconciler/polling_job_test.go +++ b/internal/cmd/controller/gitops/reconciler/polling_job_test.go @@ -12,7 +12,7 @@ import ( "go.uber.org/mock/gomock" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/tools/record" + "k8s.io/client-go/tools/events" "sigs.k8s.io/controller-runtime/pkg/client" ) @@ -27,7 +27,7 @@ func TestPollGitRepo(t *testing.T) { type testcase struct { name string gitrepo *v1alpha1.GitRepo - setupMocks func(*mocks.MockK8sClient, *mocks.MockStatusWriter, *gitmocks.MockGitFetcher, *record.FakeRecorder) + setupMocks func(*mocks.MockK8sClient, *mocks.MockStatusWriter, *gitmocks.MockGitFetcher, *events.FakeRecorder) patchErr string expectedErr string expectedEvents []string @@ -42,7 +42,7 @@ func TestPollGitRepo(t *testing.T) { Spec: v1alpha1.GitRepoSpec{Repo: repoURL, Branch: branch}, Status: v1alpha1.GitRepoStatus{Commit: "old-commit"}, }, - setupMocks: func(c *mocks.MockK8sClient, sw *mocks.MockStatusWriter, gf *gitmocks.MockGitFetcher, r *record.FakeRecorder) { + setupMocks: func(c *mocks.MockK8sClient, sw *mocks.MockStatusWriter, gf *gitmocks.MockGitFetcher, r *events.FakeRecorder) { nsName := types.NamespacedName{Name: name, Namespace: namespace} c.EXPECT().Get(gomock.Any(), nsName, gomock.Any()).Times(2).DoAndReturn(func(_ context.Context, _ types.NamespacedName, obj *v1alpha1.GitRepo, _ ...client.GetOption) error { obj.Name = name @@ -74,7 +74,7 @@ func TestPollGitRepo(t *testing.T) { Spec: v1alpha1.GitRepoSpec{Repo: repoURL, Branch: branch}, Status: v1alpha1.GitRepoStatus{Commit: "same-commit"}, }, - setupMocks: func(c *mocks.MockK8sClient, sw *mocks.MockStatusWriter, gf *gitmocks.MockGitFetcher, r *record.FakeRecorder) { + setupMocks: func(c *mocks.MockK8sClient, sw *mocks.MockStatusWriter, gf *gitmocks.MockGitFetcher, r *events.FakeRecorder) { c.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any()).Times(2).DoAndReturn(func(_ context.Context, _ client.ObjectKey, obj *v1alpha1.GitRepo, _ ...client.GetOption) error { obj.Name = name obj.Namespace = namespace @@ -99,7 +99,7 @@ func TestPollGitRepo(t *testing.T) { ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: namespace}, Spec: v1alpha1.GitRepoSpec{Repo: repoURL, Branch: branch}, }, - setupMocks: func(c *mocks.MockK8sClient, sw *mocks.MockStatusWriter, gf *gitmocks.MockGitFetcher, r *record.FakeRecorder) { + setupMocks: func(c *mocks.MockK8sClient, sw *mocks.MockStatusWriter, gf *gitmocks.MockGitFetcher, r *events.FakeRecorder) { nsName := types.NamespacedName{Name: name, Namespace: namespace} c.EXPECT().Get(gomock.Any(), nsName, gomock.Any()).Times(2).DoAndReturn(func(_ context.Context, _ client.ObjectKey, obj *v1alpha1.GitRepo, _ ...client.GetOption) error { obj.Name = name @@ -128,7 +128,7 @@ func TestPollGitRepo(t *testing.T) { ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: namespace}, Spec: v1alpha1.GitRepoSpec{Repo: repoURL, Branch: branch}, }, - setupMocks: func(c *mocks.MockK8sClient, sw *mocks.MockStatusWriter, gf *gitmocks.MockGitFetcher, r *record.FakeRecorder) { + setupMocks: func(c *mocks.MockK8sClient, sw *mocks.MockStatusWriter, gf *gitmocks.MockGitFetcher, r *events.FakeRecorder) { nsName := types.NamespacedName{Name: name, Namespace: namespace} c.EXPECT().Get(gomock.Any(), nsName, gomock.Any()).Times(3).DoAndReturn(func(_ context.Context, _ client.ObjectKey, obj *v1alpha1.GitRepo, _ ...client.GetOption) error { obj.Name = name @@ -154,7 +154,7 @@ func TestPollGitRepo(t *testing.T) { mockClient := mocks.NewMockK8sClient(ctrl) mockStatusWriter := mocks.NewMockStatusWriter(ctrl) mockGitFetcher := gitmocks.NewMockGitFetcher(ctrl) - recorder := record.NewFakeRecorder(10) + recorder := events.NewFakeRecorder(10) if tc.setupMocks != nil { tc.setupMocks(mockClient, mockStatusWriter, mockGitFetcher, recorder) diff --git a/internal/cmd/controller/helmops/operator.go b/internal/cmd/controller/helmops/operator.go index ea4c2adc73..ba68c530b9 100644 --- a/internal/cmd/controller/helmops/operator.go +++ b/internal/cmd/controller/helmops/operator.go @@ -119,7 +119,7 @@ func (g *HelmOperator) Run(cmd *cobra.Command, args []string) error { Scheduler: sched, Workers: workers, ShardID: g.ShardID, - Recorder: mgr.GetEventRecorderFor(fmt.Sprintf("fleet-helmops%s", shardIDSuffix)), + Recorder: mgr.GetEventRecorder(fmt.Sprintf("fleet-helmops%s", shardIDSuffix)), } helmOpStatusReconciler := &reconciler.HelmOpStatusReconciler{ diff --git a/internal/cmd/controller/helmops/reconciler/helmop_controller.go b/internal/cmd/controller/helmops/reconciler/helmop_controller.go index 0138f67b29..3210a54b8e 100644 --- a/internal/cmd/controller/helmops/reconciler/helmop_controller.go +++ b/internal/cmd/controller/helmops/reconciler/helmop_controller.go @@ -14,7 +14,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" errutil "k8s.io/apimachinery/pkg/util/errors" - "k8s.io/client-go/tools/record" + "k8s.io/client-go/tools/events" "k8s.io/client-go/util/retry" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/builder" @@ -47,7 +47,7 @@ type HelmOpReconciler struct { Scheduler quartz.Scheduler Workers int ShardID string - Recorder record.EventRecorder + Recorder events.EventRecorder } func (r *HelmOpReconciler) SetupWithManager(mgr ctrl.Manager) error { diff --git a/internal/cmd/controller/helmops/reconciler/polling_job.go b/internal/cmd/controller/helmops/reconciler/polling_job.go index 772027f9dd..9d4faf28f4 100644 --- a/internal/cmd/controller/helmops/reconciler/polling_job.go +++ b/internal/cmd/controller/helmops/reconciler/polling_job.go @@ -13,15 +13,15 @@ import ( "golang.org/x/sync/semaphore" fleet "github.com/rancher/fleet/pkg/apis/fleet.cattle.io/v1alpha1" - fleetevent "github.com/rancher/fleet/pkg/event" "github.com/rancher/wrangler/v3/pkg/condition" "github.com/rancher/wrangler/v3/pkg/kstatus" + corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" errutil "k8s.io/apimachinery/pkg/util/errors" - "k8s.io/client-go/tools/record" + "k8s.io/client-go/tools/events" "k8s.io/client-go/util/retry" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/log" @@ -40,12 +40,12 @@ type helmPollingJob struct { chart string version string - recorder record.EventRecorder + recorder events.EventRecorder } func newHelmPollingJob( c client.Client, - r record.EventRecorder, + r events.EventRecorder, namespace, name string, helmRef fleet.HelmOptions, @@ -116,9 +116,17 @@ func (j *helmPollingJob) pollHelm(ctx context.Context) error { // Even if it fails, this timestamp will be updated in the HelmOp status. pollingTimestamp := time.Now().UTC() - fail := func(origErr error, eventReason string) error { + fail := func(origErr error, eventReason, eventAction string) error { if eventReason != "" { - j.recorder.Event(h, fleetevent.Warning, eventReason, origErr.Error()) + j.recorder.Eventf( + h, + nil, + corev1.EventTypeWarning, + eventReason, + eventAction, + "%v", + origErr, + ) } return j.updateErrorStatus(ctx, h, pollingTimestamp, origErr) @@ -126,20 +134,32 @@ func (j *helmPollingJob) pollHelm(ctx context.Context) error { version, err := getChartVersion(ctx, j.client, *h) if err != nil { - return fail(err, "FailedToGetNewChartVersion") + return fail(err, "FailedToGetNewChartVersion", "GetNewChartVersion") } b := &fleet.Bundle{} if err := j.client.Get(ctx, nsName, b); err != nil { - return fail(fmt.Errorf("could not get bundle before patching its version: %w", err), "FailedToGetBundle") + return fail( + fmt.Errorf("could not get bundle before patching its version: %w", err), + "FailedToGetBundle", + "GetBundle", + ) } orig := b.DeepCopy() b.Spec.Helm.Version = version if version != h.Status.Version { - j.recorder.Event(h, fleetevent.Normal, "GotNewChartVersion", version) + j.recorder.Eventf( + h, + nil, + corev1.EventTypeNormal, + "GotNewChartVersion", + "GetNewChartVersion", + "%s", + version, + ) } patch := client.MergeFrom(orig) @@ -149,7 +169,11 @@ func (j *helmPollingJob) pollHelm(ctx context.Context) error { } if err := j.client.Patch(ctx, b, patch); err != nil { - return fail(fmt.Errorf("could not patch bundle to set the resolved version: %w", err), "FailedToPatchBundle") + return fail( + fmt.Errorf("could not patch bundle to set the resolved version: %w", err), + "FailedToPatchBundle", + "PatchBundle", + ) } nsn := types.NamespacedName{Name: h.Name, Namespace: h.Namespace} @@ -180,6 +204,7 @@ func (j *helmPollingJob) pollHelm(ctx context.Context) error { return fail( fmt.Errorf("could not update HelmOp status with polling timestamp: %w", err), "FailedToUpdateHelmOpStatus", + "UpdateHelmOpStatus", ) } diff --git a/internal/cmd/controller/operator.go b/internal/cmd/controller/operator.go index 143d7214c8..59bf253f78 100644 --- a/internal/cmd/controller/operator.go +++ b/internal/cmd/controller/operator.go @@ -120,7 +120,7 @@ func start( if err = (&reconciler.BundleReconciler{ Client: mgr.GetClient(), Scheme: mgr.GetScheme(), - Recorder: mgr.GetEventRecorderFor(fmt.Sprintf("fleet-bundle-ctrl%s", shardIDSuffix)), //nolint:staticcheck // GetEventRecorderFor is deprecated + Recorder: mgr.GetEventRecorder(fmt.Sprintf("fleet-bundle-ctrl%s", shardIDSuffix)), APIReader: mgr.GetAPIReader(), Builder: builder, @@ -190,7 +190,7 @@ func start( if err = (&reconciler.ScheduleReconciler{ Client: mgr.GetClient(), Scheme: mgr.GetScheme(), - Recorder: mgr.GetEventRecorderFor(fmt.Sprintf("fleet-schedule-ctrl%s", shardIDSuffix)), + Recorder: mgr.GetEventRecorder(fmt.Sprintf("fleet-schedule-ctrl%s", shardIDSuffix)), ShardID: shardID, Workers: workersOpts.Schedule, diff --git a/internal/cmd/controller/reconciler/bundle_controller.go b/internal/cmd/controller/reconciler/bundle_controller.go index 3f47f14319..bb546c9f96 100644 --- a/internal/cmd/controller/reconciler/bundle_controller.go +++ b/internal/cmd/controller/reconciler/bundle_controller.go @@ -27,7 +27,6 @@ import ( "github.com/rancher/fleet/internal/ocistorage" fleet "github.com/rancher/fleet/pkg/apis/fleet.cattle.io/v1alpha1" "github.com/rancher/fleet/pkg/durations" - fleetevent "github.com/rancher/fleet/pkg/event" "github.com/rancher/fleet/pkg/sharding" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" @@ -36,7 +35,7 @@ import ( "k8s.io/apimachinery/pkg/types" errutil "k8s.io/apimachinery/pkg/util/errors" "k8s.io/apimachinery/pkg/util/sets" - "k8s.io/client-go/tools/record" + "k8s.io/client-go/tools/events" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/builder" "sigs.k8s.io/controller-runtime/pkg/client" @@ -71,7 +70,7 @@ type TargetBuilder interface { type BundleReconciler struct { client.Client Scheme *runtime.Scheme - Recorder record.EventRecorder + Recorder events.EventRecorder APIReader client.Reader Builder TargetBuilder @@ -911,7 +910,17 @@ func (r *BundleReconciler) maybeDeleteOCIArtifact(ctx context.Context, bundle *f } err = ocistorage.NewOCIWrapper().DeleteManifest(ctx, opts, bundle.Spec.ContentsID) if err != nil { - r.Recorder.Event(bundle, fleetevent.Warning, "FailedToDeleteOCIArtifact", fmt.Sprintf("deleting OCI artifact %q: %v", bundle.Spec.ContentsID, err.Error())) + r.Recorder.Eventf( + bundle, + nil, + corev1.EventTypeWarning, + "FailedToDeleteOCIArtifact", + "DeleteOCIArtifact", + "deleting OCI artifact %q: %v", + bundle.Spec.ContentsID, + "%v", + err, + ) } // In case there's an error deleting from the OCI registry, diff --git a/internal/cmd/controller/reconciler/schedule_controller.go b/internal/cmd/controller/reconciler/schedule_controller.go index 5ae77c5c10..65b4a3dc40 100644 --- a/internal/cmd/controller/reconciler/schedule_controller.go +++ b/internal/cmd/controller/reconciler/schedule_controller.go @@ -19,7 +19,7 @@ import ( "k8s.io/apimachinery/pkg/api/equality" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/tools/record" + "k8s.io/client-go/tools/events" "k8s.io/client-go/util/retry" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/builder" @@ -35,7 +35,7 @@ import ( type ScheduleReconciler struct { client.Client Scheme *runtime.Scheme - Recorder record.EventRecorder + Recorder events.EventRecorder ShardID string Workers int Scheduler quartz.Scheduler diff --git a/internal/cmd/controller/reconciler/schedule_controller_test.go b/internal/cmd/controller/reconciler/schedule_controller_test.go index 95551ea6f5..25982d5313 100644 --- a/internal/cmd/controller/reconciler/schedule_controller_test.go +++ b/internal/cmd/controller/reconciler/schedule_controller_test.go @@ -14,7 +14,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/kubernetes/scheme" - "k8s.io/client-go/tools/record" + "k8s.io/client-go/tools/events" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" "sigs.k8s.io/controller-runtime/pkg/reconcile" @@ -95,7 +95,7 @@ var _ = Describe("ScheduleReconciler", func() { Client: k8sclient, Scheme: scheme.Scheme, Scheduler: scheduler, - Recorder: record.NewFakeRecorder(10), + Recorder: events.NewFakeRecorder(10), } }) diff --git a/internal/mocks/eventrecorder_mock.go b/internal/mocks/eventrecorder_mock.go index edf5528b6d..6b873b5319 100644 --- a/internal/mocks/eventrecorder_mock.go +++ b/internal/mocks/eventrecorder_mock.go @@ -1,5 +1,10 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: k8s.io/client-go/tools/record (interfaces: EventRecorder) +// Source: k8s.io/client-go/tools/events (interfaces: EventRecorder) +// +// Generated by this command: +// +// mockgen --build_flags=--mod=mod -destination=./internal/mocks/eventrecorder_mock.go -package=mocks k8s.io/client-go/tools/events EventRecorder +// // Package mocks is a generated GoMock package. package mocks @@ -15,6 +20,7 @@ import ( type MockEventRecorder struct { ctrl *gomock.Controller recorder *MockEventRecorderMockRecorder + isgomock struct{} } // MockEventRecorderMockRecorder is the mock recorder for MockEventRecorder. @@ -34,48 +40,19 @@ func (m *MockEventRecorder) EXPECT() *MockEventRecorderMockRecorder { return m.recorder } -// AnnotatedEventf mocks base method. -func (m *MockEventRecorder) AnnotatedEventf(arg0 runtime.Object, arg1 map[string]string, arg2, arg3, arg4 string, arg5 ...interface{}) { - m.ctrl.T.Helper() - varargs := []interface{}{arg0, arg1, arg2, arg3, arg4} - for _, a := range arg5 { - varargs = append(varargs, a) - } - m.ctrl.Call(m, "AnnotatedEventf", varargs...) -} - -// AnnotatedEventf indicates an expected call of AnnotatedEventf. -func (mr *MockEventRecorderMockRecorder) AnnotatedEventf(arg0, arg1, arg2, arg3, arg4 interface{}, arg5 ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{arg0, arg1, arg2, arg3, arg4}, arg5...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AnnotatedEventf", reflect.TypeOf((*MockEventRecorder)(nil).AnnotatedEventf), varargs...) -} - -// Event mocks base method. -func (m *MockEventRecorder) Event(arg0 runtime.Object, arg1, arg2, arg3 string) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "Event", arg0, arg1, arg2, arg3) -} - -// Event indicates an expected call of Event. -func (mr *MockEventRecorderMockRecorder) Event(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Event", reflect.TypeOf((*MockEventRecorder)(nil).Event), arg0, arg1, arg2, arg3) -} - // Eventf mocks base method. -func (m *MockEventRecorder) Eventf(arg0 runtime.Object, arg1, arg2, arg3 string, arg4 ...interface{}) { +func (m *MockEventRecorder) Eventf(regarding, related runtime.Object, eventtype, reason, action, note string, args ...any) { m.ctrl.T.Helper() - varargs := []interface{}{arg0, arg1, arg2, arg3} - for _, a := range arg4 { + varargs := []any{regarding, related, eventtype, reason, action, note} + for _, a := range args { varargs = append(varargs, a) } m.ctrl.Call(m, "Eventf", varargs...) } // Eventf indicates an expected call of Eventf. -func (mr *MockEventRecorderMockRecorder) Eventf(arg0, arg1, arg2, arg3 interface{}, arg4 ...interface{}) *gomock.Call { +func (mr *MockEventRecorderMockRecorder) Eventf(regarding, related, eventtype, reason, action, note any, args ...any) *gomock.Call { mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{arg0, arg1, arg2, arg3}, arg4...) + varargs := append([]any{regarding, related, eventtype, reason, action, note}, args...) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Eventf", reflect.TypeOf((*MockEventRecorder)(nil).Eventf), varargs...) }