From 92400d29fc4cd99ce7db171e1b9f9126bb782922 Mon Sep 17 00:00:00 2001 From: Adrian Fernandez De La Torre Date: Sat, 14 Mar 2026 18:30:03 +0100 Subject: [PATCH] Migrate event recorder to fluxcd/pkg/runtime/events.Recorder - Replace kuberecorder.EventRecorder with events.Recorder to support structured event metadata including source object and action type - Upgrade event API from event/v1beta1 to event/v1 - Add action parameter (Reconciled, Failed, Waiting, Applied, Deleted, Progressing) to all event calls for richer event semantics - Pass source reference through reconcile, apply, prune, checkHealth, and finalize methods - Update tests to use events.Recorder Signed-off-by: Adrian Fernandez De La Torre --- go.mod | 28 ++++---- go.sum | 60 ++++++++-------- .../kustomization_commit_status_test.go | 14 ++-- .../controller/kustomization_controller.go | 72 ++++++++++++------- .../kustomization_controller_test.go | 8 +-- .../kustomization_decryptor_test.go | 12 ++-- .../kustomization_externalartifact_test.go | 22 +++--- .../controller/kustomization_force_test.go | 12 ++-- .../controller/kustomization_fuzzer_test.go | 28 ++------ .../kustomization_origin_revision_test.go | 12 ++-- .../controller/kustomization_wait_test.go | 30 ++++---- internal/controller/suite_test.go | 40 ++++------- main.go | 4 +- 13 files changed, 171 insertions(+), 171 deletions(-) diff --git a/go.mod b/go.mod index 00aaad625..0d0537891 100644 --- a/go.mod +++ b/go.mod @@ -28,7 +28,7 @@ require ( github.com/fluxcd/pkg/cache v0.15.0 github.com/fluxcd/pkg/http/fetch v0.26.0 github.com/fluxcd/pkg/kustomize v1.41.0 - github.com/fluxcd/pkg/runtime v0.112.0 + github.com/fluxcd/pkg/runtime v0.113.0 github.com/fluxcd/pkg/ssa v0.78.0 github.com/fluxcd/pkg/tar v1.2.0 github.com/fluxcd/pkg/testserver v0.14.0 @@ -81,7 +81,7 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.2.0 // indirect github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect github.com/AzureAD/microsoft-authentication-library-for-go v1.8.0 // indirect - github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.33.0 // indirect + github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.36.0 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.57.0 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.57.0 // indirect github.com/MakeNowJust/heredoc v1.0.0 // indirect @@ -184,7 +184,7 @@ require ( github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.202 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/json-iterator/go v1.1.13-0.20220915233716-71ac16282d12 // indirect - github.com/klauspost/cpuid/v2 v2.2.10 // indirect + github.com/klauspost/cpuid/v2 v2.3.0 // indirect github.com/kylelemons/godebug v1.1.0 // indirect github.com/lib/pq v1.12.3 // indirect github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect @@ -202,7 +202,7 @@ require ( github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/opencontainers/go-digest/blake3 v0.0.0-20250116041648-1e56c6daea3b // indirect + github.com/opencontainers/go-digest/blake3 v0.0.0-20260423074420-acc66fb5367c // indirect github.com/opencontainers/image-spec v1.1.1 // indirect github.com/opencontainers/runc v1.3.6 // indirect github.com/peterbourgon/diskv v2.0.1+incompatible // indirect @@ -234,20 +234,20 @@ require ( github.com/zeebo/blake3 v0.2.4 // indirect go.mongodb.org/mongo-driver v1.17.9 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect - go.opentelemetry.io/contrib/detectors/gcp v1.44.0 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.69.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0 // indirect - go.opentelemetry.io/otel v1.44.0 // indirect - go.opentelemetry.io/otel/metric v1.44.0 // indirect - go.opentelemetry.io/otel/sdk v1.44.0 // indirect - go.opentelemetry.io/otel/sdk/metric v1.44.0 // indirect - go.opentelemetry.io/otel/trace v1.44.0 // indirect + go.opentelemetry.io/contrib/detectors/gcp v1.46.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.71.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.71.0 // indirect + go.opentelemetry.io/otel v1.46.0 // indirect + go.opentelemetry.io/otel/metric v1.46.0 // indirect + go.opentelemetry.io/otel/sdk v1.46.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.46.0 // indirect + go.opentelemetry.io/otel/trace v1.46.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.1 // indirect go.yaml.in/yaml/v2 v2.4.4 // indirect go.yaml.in/yaml/v3 v3.0.5 // indirect golang.org/x/crypto v0.56.0 // indirect - golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f // indirect + golang.org/x/exp v0.0.0-20260824195058-e88cd73687aa // indirect golang.org/x/sync v0.22.0 // indirect golang.org/x/sys v0.47.0 // indirect golang.org/x/term v0.45.0 // indirect @@ -257,7 +257,7 @@ require ( google.golang.org/api v0.297.0 // indirect google.golang.org/genproto v0.0.0-20260715232425-e75dac1f907d // indirect google.golang.org/genproto/googleapis/api v0.0.0-20260715232425-e75dac1f907d // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20260819154853-08b0e4226688 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260825221802-da73d73af1c5 // indirect google.golang.org/grpc v1.83.2 // indirect google.golang.org/protobuf v1.36.12 // indirect gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect diff --git a/go.sum b/go.sum index 261220ad9..6b71b40f5 100644 --- a/go.sum +++ b/go.sum @@ -59,8 +59,8 @@ github.com/AzureAD/microsoft-authentication-library-for-go v1.8.0 h1:Nljr4q1GRA/ github.com/AzureAD/microsoft-authentication-library-for-go v1.8.0/go.mod h1:Y33QHnf0FfdVewFFISOGe20mkZbxX4H839o955/PoeI= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.33.0 h1:l7+6kwRMJNwdCvYdDl7Eax+wzEYHSnNY7zrrfbhDdTA= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.33.0/go.mod h1:pJTkW8hEUIIi3Pf65lPZOnn4Y81yCllX6IWk2jNXdkM= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.36.0 h1:3SdxXLkgAfiHRWcGTq6fneq9jgoJzneiY0yPQnjoT2E= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.36.0/go.mod h1:1iIdl0k+ppn9wT0wzR9H7HkSvIui/4qgtnKW10cQtds= github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.57.0 h1:jLdiS1vO+XJFyDSWRHBx56r4s/NNtcl5J6KyCcWUX/w= github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.57.0/go.mod h1:8lmpHY+1VRoteiOwyrQMDt1YGXOrFKCz+1wJW7n3ODY= github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.57.0 h1:cSjUzZ7KU8hicTgzaSv9NmSyM9fTVK3y5lsBUl3wOis= @@ -221,8 +221,8 @@ github.com/fluxcd/pkg/http/fetch v0.26.0 h1:Q+KTDLzUa7gfVqHiVpuk/dRD8hG67qmWlerB github.com/fluxcd/pkg/http/fetch v0.26.0/go.mod h1:EvqNTeKGUkU5UcrvWrkpge4rYc7QBScp29+XK7Kmqsc= github.com/fluxcd/pkg/kustomize v1.41.0 h1:ShntVMiX8ZvvQCM3MNIaxZbYT4T4ehV2wIWC73rzBrg= github.com/fluxcd/pkg/kustomize v1.41.0/go.mod h1:fjTYKu3tdKid84b4nEeSc+9DVmRgtxcx8UtyhS0yzOw= -github.com/fluxcd/pkg/runtime v0.112.0 h1:FnE+98Fg2LJYRBxMYGOIuE4C7nwtLMCXxFFJpMizdsA= -github.com/fluxcd/pkg/runtime v0.112.0/go.mod h1:YUljTAXVaeWG+GLnXNZopFFMZstUoTxJs7+vl91OV58= +github.com/fluxcd/pkg/runtime v0.113.0 h1:DzO7IEoNU+srL9aHjTGdsMawR33A9bfk7rCHRZZKiac= +github.com/fluxcd/pkg/runtime v0.113.0/go.mod h1:+h0Fyn5VfqFklfXxQJ0cuTxdS6RfE0qCwsSJa09vwy0= github.com/fluxcd/pkg/sourceignore v0.19.0 h1:s3/E03o9JTAvjIE7K8vI257AT2+0zy8cFOFaX+lx0z8= github.com/fluxcd/pkg/sourceignore v0.19.0/go.mod h1:MYwDEmDdj5GjHg1r1ljgtNkXNGkeV42G8BnCsggqExg= github.com/fluxcd/pkg/ssa v0.78.0 h1:Wzm9uoYLDUCRV2SlJuBLkOQu/OnPKuTWyTzIFZbpVfY= @@ -385,8 +385,8 @@ github.com/keybase/go-keychain v0.0.1/go.mod h1:PdEILRW3i9D8JcdM+FmY6RwkHGnhHxXw github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.19.2 h1:hMRETovs/pu/dVWN7zIT1PGG8t509MwT6bO7XSi26R8= github.com/klauspost/compress v1.19.2/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= -github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE= -github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= +github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= +github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= @@ -433,8 +433,8 @@ github.com/onsi/gomega v1.43.0 h1:VlG/1FxqNxhSO+lq/OHBNaaqwiBK/mO8JbVkX9Y+FeU= github.com/onsi/gomega v1.43.0/go.mod h1:REff/hsDsodHoKlWsP2mAPhu1+5/6hVYNf9rIEBpeSg= github.com/opencontainers/go-digest v1.0.1-0.20220411205349-bde1400a84be h1:f2PlhC9pm5sqpBZFvnAoKj+KzXRzbjFMA+TqXfJdgho= github.com/opencontainers/go-digest v1.0.1-0.20220411205349-bde1400a84be/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= -github.com/opencontainers/go-digest/blake3 v0.0.0-20250116041648-1e56c6daea3b h1:nAiL9bmUK4IzFrKoVMRykv0iYGdoit5vpbPaVCZ+fI4= -github.com/opencontainers/go-digest/blake3 v0.0.0-20250116041648-1e56c6daea3b/go.mod h1:kqQaIc6bZstKgnGpL7GD5dWoLKbA6mH1Y9ULjGImBnM= +github.com/opencontainers/go-digest/blake3 v0.0.0-20260423074420-acc66fb5367c h1:hoXeyseDmGKvktiX5XyqSJN/Irag06SnsxIeuaHdRIE= +github.com/opencontainers/go-digest/blake3 v0.0.0-20260423074420-acc66fb5367c/go.mod h1:kqQaIc6bZstKgnGpL7GD5dWoLKbA6mH1Y9ULjGImBnM= github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= github.com/opencontainers/runc v1.3.6 h1:SLGIymCtsk80iNPWgbc8dtjI30r+5mTVV+4dN8/17Sk= @@ -542,26 +542,26 @@ go.mongodb.org/mongo-driver v1.17.9 h1:IexDdCuuNJ3BHrELgBlyaH9p60JXAvdzWR128q+U5 go.mongodb.org/mongo-driver v1.17.9/go.mod h1:LlOhpH5NUEfhxcAwG0UEkMqwYcc4JU18gtCdGudk/tQ= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= -go.opentelemetry.io/contrib/detectors/gcp v1.44.0 h1:NmLfL734pJhM0JKaYd2Y28+nY9dPRWYAAbxhRCrKXPw= -go.opentelemetry.io/contrib/detectors/gcp v1.44.0/go.mod h1:tNAsgd8avTGke1+MndXlU5Cru4PQ9Ai/cCNWQv/ZJ/s= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.69.0 h1:2yEATaop1/a1I4psnSLgWVPLWwCzkqWakgJy7xTDVy0= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.69.0/go.mod h1:D7J12YRapIekYyPWgGPlA/23pRmpSEZC5xJC/TTLI9U= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0 h1:8tvICD4vSTOOsNrsI4Ljf6C+6UKvpTEH5XY3JMoyPoo= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0/go.mod h1:z9+yiacE0IHRqM4qFfkbt/JYlmYXgss8GY/jXoNuPJI= -go.opentelemetry.io/otel v1.44.0 h1:JjwHmHpA4iZ3wBxluu2fbbE7j4kqlE8jXyAyPXH7HqU= -go.opentelemetry.io/otel v1.44.0/go.mod h1:BMgjTHL9WPRlRjL2oZCBTL4whCGtXch2H4BhOPIAyYc= +go.opentelemetry.io/contrib/detectors/gcp v1.46.0 h1:PI8dGkqDaQkwJ8kOopqMhDTbrnK3UIeG/RCHH4HErbo= +go.opentelemetry.io/contrib/detectors/gcp v1.46.0/go.mod h1:nsrN5c/sOLoY2vsPxN/rQ0V0nvGrWJCqcW4UXLtqNG8= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.71.0 h1:B2h3uqicet1CT2N5TOFhS+Gq++9i0/CLmaxvhmhtP5s= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.71.0/go.mod h1:dylvB+ZiiwMvsDij9O84Uy7SijLgHMX4mbkncds+4Sw= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.71.0 h1:3g7B90UzBltIDKq1/5mrTGxTnOFDV0ICOhLoxiZ8jlg= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.71.0/go.mod h1:Ef8SuTh59BT7+ofpDxN9z+yOlc4t2GjLmKDgYNJL/NU= +go.opentelemetry.io/otel v1.46.0 h1:FHt5/CDyVxi/8IM1CH7VE/rRgq3kLHa2mSTVMO8AWyc= +go.opentelemetry.io/otel v1.46.0/go.mod h1:Gj3SEScelsNC45tp4nSxRYlS+f5iez7W8XPMCt905kE= go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.44.0 h1:hqxVTu/GtBF+vJ8d1fzW7fRxZFvgoDjWcxwwCaFDYpU= go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.44.0/go.mod h1:z5fVEF4X5v0ESvlJqBrrFlBVoj5EQuefZpzsu7R+x5Q= -go.opentelemetry.io/otel/metric v1.44.0 h1:1w0gILTcHdr3YI+ixLyjemwrVnsMURbTZFrSYCdDdmc= -go.opentelemetry.io/otel/metric v1.44.0/go.mod h1:8O7hanEPBNgEMmybD3s2VBKcgWOCsA6tzHBPODAiquo= -go.opentelemetry.io/otel/metric/x v0.66.0 h1:YkCrx1zLOChi9ZcZ6euupOcsgzbVlec7D/xoEU1+cTA= -go.opentelemetry.io/otel/metric/x v0.66.0/go.mod h1:d1+BDj9t96do0/1LoU1ayfCv79ZgNE41qbhBvnMOBZk= -go.opentelemetry.io/otel/sdk v1.44.0 h1:nHYwb9lK+fJPU/dnT6s7W7Z8itMWyqrnVfbheVYrZ58= -go.opentelemetry.io/otel/sdk v1.44.0/go.mod h1:Osuydd3Se74nqjAKxid74N5eC+jfEqfTegHRnq58oK0= -go.opentelemetry.io/otel/sdk/metric v1.44.0 h1:3LlKgI+VjbVsjNRFZJZAJ30WjXC5VkNRks6si09iEfI= -go.opentelemetry.io/otel/sdk/metric v1.44.0/go.mod h1:5B5pMARnXxKhltooO4xUuCBorl65a4EpnTalObqOigA= -go.opentelemetry.io/otel/trace v1.44.0 h1:jxF5CsGYCe74MCRx2X4g7WsY/VBKRqqpNvXlX/6gtIk= -go.opentelemetry.io/otel/trace v1.44.0/go.mod h1:oLl1jrMQAVo6v3GAggN+1VH9VIz9iUSvW53sW1Q8PIE= +go.opentelemetry.io/otel/metric v1.46.0 h1:yBnkXvgV7AXFILZc5K6IZe/CBFF3OS7BJ8ov6/lj0K8= +go.opentelemetry.io/otel/metric v1.46.0/go.mod h1:iPmdWqifKUdzziPkvvzIJXITl56fQx2mGM/DHLB3/2o= +go.opentelemetry.io/otel/metric/x v0.68.0 h1:TA/cBT23D3MnxYPwHL7YFOdYGdx0A0v+s7Mzotpd1dU= +go.opentelemetry.io/otel/metric/x v0.68.0/go.mod h1:agudOmvWhwUTjgibWDzxD2PoWYnpw5Ht5jISYOD2Hd4= +go.opentelemetry.io/otel/sdk v1.46.0 h1:h5CNQQjEbuQXY/JfZtgt3i7HVFV3aHPO2OAwO2eTYPI= +go.opentelemetry.io/otel/sdk v1.46.0/go.mod h1:GAERFXFt5SYCEB+YiKUbMBeza6UaDH7GmGOZEfh2gSM= +go.opentelemetry.io/otel/sdk/metric v1.46.0 h1:0piZ26EG4RBfebb2jhDH6ERCYHoVWduc3kLgPCwSnSE= +go.opentelemetry.io/otel/sdk/metric v1.46.0/go.mod h1:I1PbKrdVc8Qu8HYVDNtqVIwLwjNrhsV/uFuxfwg8mO4= +go.opentelemetry.io/otel/trace v1.46.0 h1:OULy7ccdJnZtJ0UDYFOIGaCmiWzJ8Vi2G/Rsu60qs1c= +go.opentelemetry.io/otel/trace v1.46.0/go.mod h1:J7GAXweO77XSFkB/rmAqk9D6ihszhFjLU+d9WuUxDLI= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= @@ -581,8 +581,8 @@ golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0 golang.org/x/crypto v0.56.0 h1:GUh5Ii4J5jtcseSMiRqr1jXCNHoxjeV9Fmekc2oLy6Y= golang.org/x/crypto v0.56.0/go.mod h1:OMW5y6CY9l38uPLmxU6l6pwcXp1obtLo3e6gT7gQR2I= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f h1:W3F4c+6OLc6H2lb//N1q4WpJkhzJCK5J6kUi1NTVXfM= -golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f/go.mod h1:J1xhfL/vlindoeF/aINzNzt2Bket5bjo9sdOYzOsU80= +golang.org/x/exp v0.0.0-20260824195058-e88cd73687aa h1:QSyA8ishJCyT21kER9KwNt0b7BM3iRK4x9QXhjN5Fdk= +golang.org/x/exp v0.0.0-20260824195058-e88cd73687aa/go.mod h1:zeBbvyFKDaLwa7CH/zI8KXt7gTl14SF7sO08Pl5jBCM= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= @@ -667,8 +667,8 @@ google.golang.org/genproto v0.0.0-20260715232425-e75dac1f907d h1:C9v1o0/4quuhOAf google.golang.org/genproto v0.0.0-20260715232425-e75dac1f907d/go.mod h1:Wz2wFJntZFmLGo7pLDXZ3wYk5hyc0Mb+SkHhDDXT+lU= google.golang.org/genproto/googleapis/api v0.0.0-20260715232425-e75dac1f907d h1:QwnJwPte4XXAkhPu26LTDIahnsMSUV0kK8HkxbC+Pc4= google.golang.org/genproto/googleapis/api v0.0.0-20260715232425-e75dac1f907d/go.mod h1:WRrQ7/7N19PypuT0fxLOL5Lq0waoiRri4FbtHDEKrGE= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260819154853-08b0e4226688 h1:cYNAzI2sUwhmCcoj9TxvihSrqsxt6uIkj3rDRhSDmW4= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260819154853-08b0e4226688/go.mod h1:DjtHYE8FKJLivXcBEjGwndXfIC23G0VpXiXKqG179uA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260825221802-da73d73af1c5 h1:1VUiZAXyC+zmiFYi+WLtBzr68Cj8wOofHjjrA/kkizc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260825221802-da73d73af1c5/go.mod h1:DjtHYE8FKJLivXcBEjGwndXfIC23G0VpXiXKqG179uA= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= diff --git a/internal/controller/kustomization_commit_status_test.go b/internal/controller/kustomization_commit_status_test.go index 522ce49be..9ac8b0ee4 100644 --- a/internal/controller/kustomization_commit_status_test.go +++ b/internal/controller/kustomization_commit_status_test.go @@ -21,12 +21,13 @@ import ( "testing" "time" - eventv1 "github.com/fluxcd/pkg/apis/event/v1beta1" + eventv1 "github.com/fluxcd/pkg/apis/event/v1" "github.com/fluxcd/pkg/apis/meta" + "github.com/fluxcd/pkg/runtime/testenv" "github.com/fluxcd/pkg/testserver" sourcev1 "github.com/fluxcd/source-controller/api/v1" . "github.com/onsi/gomega" - corev1 "k8s.io/api/core/v1" + eventsv1 "k8s.io/api/events/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" @@ -91,11 +92,12 @@ data: // commitStatusEvents returns the reconciliation success events carrying the // applied revision. These are the events used by notification-controller to // update the Git commit status. - commitStatusEvents := func(name string) []corev1.Event { - var result []corev1.Event - for _, event := range getEvents(name, map[string]string{ + commitStatusEvents := func(name string) []eventsv1.Event { + var result []eventsv1.Event + events, _ := testenv.GetEvents(ctx, k8sClient, name, "", map[string]string{ group + "/" + eventv1.MetaRevisionKey: revision, - }) { + }) + for _, event := range events { if event.Reason == meta.ReconciliationSucceededReason { result = append(result, event) } diff --git a/internal/controller/kustomization_controller.go b/internal/controller/kustomization_controller.go index b0ff7b6a2..6feb8b428 100644 --- a/internal/controller/kustomization_controller.go +++ b/internal/controller/kustomization_controller.go @@ -37,7 +37,6 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/types" kerrors "k8s.io/apimachinery/pkg/util/errors" - kuberecorder "k8s.io/client-go/tools/record" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" @@ -47,7 +46,7 @@ import ( "github.com/fluxcd/cli-utils/pkg/kstatus/polling/engine" "github.com/fluxcd/cli-utils/pkg/object" apiacl "github.com/fluxcd/pkg/apis/acl" - eventv1 "github.com/fluxcd/pkg/apis/event/v1beta1" + eventv1 "github.com/fluxcd/pkg/apis/event/v1" "github.com/fluxcd/pkg/apis/meta" "github.com/fluxcd/pkg/auth" authutils "github.com/fluxcd/pkg/auth/utils" @@ -59,6 +58,7 @@ import ( runtimeClient "github.com/fluxcd/pkg/runtime/client" "github.com/fluxcd/pkg/runtime/conditions" runtimeCtrl "github.com/fluxcd/pkg/runtime/controller" + "github.com/fluxcd/pkg/runtime/events" "github.com/fluxcd/pkg/runtime/jitter" "github.com/fluxcd/pkg/runtime/patch" "github.com/fluxcd/pkg/runtime/statusreaders" @@ -86,7 +86,7 @@ import ( // KustomizationReconciler reconciles a Kustomization object type KustomizationReconciler struct { client.Client - kuberecorder.EventRecorder + EventRecorder events.Recorder runtimeCtrl.Metrics // Kubernetes options @@ -139,6 +139,10 @@ func (r *KustomizationReconciler) Reconcile(ctx context.Context, req ctrl.Reques // Initialize the runtime patcher with the current version of the object. patcher := patch.NewSerialPatcher(obj, r.Client) + // The source is resolved further down the reconciliation; capture it here + // so the deferred success event can reference it as the event source. + var artifactSource sourcev1.Source + // Finalise the reconciliation and report the results. defer func() { // Patch finalizers, status and conditions. @@ -163,17 +167,19 @@ func (r *KustomizationReconciler) Reconcile(ctx context.Context, req ctrl.Reques // The success event is used by notification-controller to update // the Git commit status. Skip it when the feature gate is enabled. if !r.DisableCommitStatusEvent { - r.event(obj, obj.Status.LastAppliedRevision, obj.Status.LastAppliedOriginRevision, eventv1.EventSeverityInfo, msg, + r.event(obj, artifactSource, obj.Status.LastAppliedRevision, obj.Status.LastAppliedOriginRevision, eventv1.EventSeverityInfo, + eventv1.ActionReconciled, msg, map[string]string{ kustomizev1.GroupVersion.Group + "/" + eventv1.MetaCommitStatusKey: eventv1.MetaCommitStatusUpdateValue, - }) + }, + ) } } }() // Prune managed resources if the object is under deletion. if !obj.ObjectMeta.DeletionTimestamp.IsZero() { - return r.finalize(ctx, obj) + return r.finalize(ctx, obj, artifactSource) } // Add finalizer first if it doesn't exist to avoid the race condition @@ -198,7 +204,7 @@ func (r *KustomizationReconciler) Reconcile(ctx context.Context, req ctrl.Reques conditions.MarkFalse(obj, meta.ReadyCondition, meta.InvalidCELExpressionReason, "%s", errMsg) conditions.MarkStalled(obj, meta.InvalidCELExpressionReason, "%s", errMsg) obj.Status.ObservedGeneration = obj.Generation - r.event(obj, "", "", eventv1.EventSeverityError, errMsg, nil) + r.event(obj, artifactSource, "", "", eventv1.EventSeverityError, eventv1.ActionFailed, errMsg, nil) return ctrl.Result{}, reconcile.TerminalError(err) } @@ -210,12 +216,12 @@ func (r *KustomizationReconciler) Reconcile(ctx context.Context, req ctrl.Reques conditions.MarkFalse(obj, meta.ReadyCondition, meta.FeatureGateDisabledReason, msgFmt, gate) conditions.MarkStalled(obj, meta.FeatureGateDisabledReason, msgFmt, gate) log.Error(auth.ErrObjectLevelWorkloadIdentityNotEnabled, msg) - r.event(obj, "", "", eventv1.EventSeverityError, msg, nil) + r.event(obj, artifactSource, "", "", eventv1.EventSeverityError, eventv1.ActionFailed, msg, nil) return ctrl.Result{}, nil } // Resolve the source reference and requeue the reconciliation if the source is not found. - artifactSource, err := r.getSource(ctx, obj) + artifactSource, err = r.getSource(ctx, obj) if err != nil { conditions.MarkFalse(obj, meta.ReadyCondition, meta.ArtifactFailedReason, "%s", err) @@ -228,7 +234,7 @@ func (r *KustomizationReconciler) Reconcile(ctx context.Context, req ctrl.Reques if acl.IsAccessDenied(err) { conditions.MarkFalse(obj, meta.ReadyCondition, apiacl.AccessDeniedReason, "%s", err) conditions.MarkStalled(obj, apiacl.AccessDeniedReason, "%s", err) - r.event(obj, "", "", eventv1.EventSeverityError, err.Error(), nil) + r.event(obj, artifactSource, "", "", eventv1.EventSeverityError, eventv1.ActionFailed, err.Error(), nil) return ctrl.Result{}, reconcile.TerminalError(err) } @@ -255,7 +261,7 @@ func (r *KustomizationReconciler) Reconcile(ctx context.Context, req ctrl.Reques conditions.MarkFalse(obj, meta.ReadyCondition, meta.InvalidCELExpressionReason, "%s", errMsg) conditions.MarkStalled(obj, meta.InvalidCELExpressionReason, "%s", errMsg) obj.Status.ObservedGeneration = obj.Generation - r.event(obj, revision, originRevision, eventv1.EventSeverityError, errMsg, nil) + r.event(obj, artifactSource, revision, originRevision, eventv1.EventSeverityError, eventv1.ActionFailed, errMsg, nil) return ctrl.Result{}, err } @@ -263,7 +269,7 @@ func (r *KustomizationReconciler) Reconcile(ctx context.Context, req ctrl.Reques conditions.MarkFalse(obj, meta.ReadyCondition, meta.DependencyNotReadyReason, "%s", err) msg := fmt.Sprintf("Dependencies do not meet ready condition, retrying in %s", r.DependencyRequeueInterval.String()) log.Info(msg) - r.event(obj, revision, originRevision, eventv1.EventSeverityInfo, msg, nil) + r.event(obj, artifactSource, revision, originRevision, eventv1.EventSeverityInfo, eventv1.ActionWaiting, msg, nil) return ctrl.Result{RequeueAfter: r.DependencyRequeueInterval}, nil } log.Info("All dependencies are ready, proceeding with reconciliation") @@ -287,7 +293,7 @@ func (r *KustomizationReconciler) Reconcile(ctx context.Context, req ctrl.Reques meta.HealthCheckCanceledReason, "New reconciliation triggered by %s/%s/%s", qes.Kind, qes.Namespace, qes.Name) ctrl.LoggerFrom(ctx).Info("New reconciliation triggered, canceling health checks", "trigger", qes) - r.event(obj, revision, originRevision, eventv1.EventSeverityInfo, + r.event(obj, artifactSource, revision, originRevision, eventv1.EventSeverityInfo, eventv1.ActionProgressing, fmt.Sprintf("Health checks canceled due to new reconciliation triggered by %s/%s/%s", qes.Kind, qes.Namespace, qes.Name), nil) @@ -305,7 +311,7 @@ func (r *KustomizationReconciler) Reconcile(ctx context.Context, req ctrl.Reques obj.GetRetryInterval().String()), "revision", revision) - r.event(obj, revision, originRevision, eventv1.EventSeverityError, + r.event(obj, artifactSource, revision, originRevision, eventv1.EventSeverityError, eventv1.ActionFailed, reconcileErr.Error(), nil) return ctrl.Result{RequeueAfter: obj.GetRetryInterval()}, nil } @@ -475,7 +481,7 @@ func (r *KustomizationReconciler) reconcile( } // Validate and apply resources in stages. - drifted, changeSet, err := r.apply(ctx, resourceManager, obj, revision, originRevision, objects) + drifted, changeSet, err := r.apply(ctx, resourceManager, obj, src, revision, originRevision, objects) if err != nil { obj.Status.History.Upsert(checksum, time.Now(), time.Since(reconcileStart), meta.ReconciliationFailedReason, historyMeta) conditions.MarkFalse(obj, meta.ReadyCondition, meta.ReconciliationFailedReason, "%s", err) @@ -506,7 +512,7 @@ func (r *KustomizationReconciler) reconcile( // On failure, re-track the objects whose DELETE wasn't confirmed so that the // next reconcile retries — otherwise status.Inventory advances past them // and they leak as untracked orphans (issue #1664). - if _, survivors, err := r.prune(ctx, resourceManager, obj, revision, originRevision, staleObjects); err != nil { + if _, survivors, err := r.prune(ctx, resourceManager, obj, src, revision, originRevision, staleObjects); err != nil { inventory.Merge(obj.Status.Inventory, survivors) obj.Status.History.Upsert(checksum, time.Now(), time.Since(reconcileStart), meta.PruneFailedReason, historyMeta) conditions.MarkFalse(obj, meta.ReadyCondition, meta.PruneFailedReason, "%s", err) @@ -519,6 +525,7 @@ func (r *KustomizationReconciler) reconcile( resourceManager, patcher, obj, + src, revision, originRevision, isNewRevision, @@ -847,6 +854,7 @@ func (r *KustomizationReconciler) build(ctx context.Context, func (r *KustomizationReconciler) apply(ctx context.Context, manager *ssa.ResourceManager, obj *kustomizev1.Kustomization, + src sourcev1.Source, revision string, originRevision string, objects []*unstructured.Unstructured) (bool, *ssa.ChangeSet, error) { @@ -970,7 +978,8 @@ func (r *KustomizationReconciler) apply(ctx context.Context, // filter out the objects that have not changed for _, change := range changeSet.Entries { if HasChanged(change.Action) { - changeSetLog.WriteString(change.String() + "\n") + changeSetLog.WriteString(change.String()) + changeSetLog.WriteString("\n") } } } @@ -993,7 +1002,7 @@ func (r *KustomizationReconciler) apply(ctx context.Context, // emit event only if the server-side apply resulted in changes applyLog := strings.TrimSuffix(changeSetLog.String(), "\n") if applyLog != "" { - r.event(obj, revision, originRevision, eventv1.EventSeverityInfo, applyLog, nil) + r.event(obj, src, revision, originRevision, eventv1.EventSeverityInfo, eventv1.ActionApplied, applyLog, nil) } return applyLog != "", resultSet, nil @@ -1003,6 +1012,7 @@ func (r *KustomizationReconciler) checkHealth(ctx context.Context, manager *ssa.ResourceManager, patcher *patch.SerialPatcher, obj *kustomizev1.Kustomization, + src sourcev1.Source, revision string, originRevision string, isNewRevision bool, @@ -1080,7 +1090,7 @@ func (r *KustomizationReconciler) checkHealth(ctx context.Context, // Emit recovery event if the previous health check failed. msg := fmt.Sprintf("Health check passed in %s", time.Since(checkStart).String()) if !wasHealthy || (isNewRevision && drifted) { - r.event(obj, revision, originRevision, eventv1.EventSeverityInfo, msg, nil) + r.event(obj, src, revision, originRevision, eventv1.EventSeverityInfo, eventv1.ActionReconciled, msg, nil) } conditions.MarkTrue(obj, meta.HealthyCondition, meta.SucceededReason, "%s", msg) @@ -1100,6 +1110,7 @@ func (r *KustomizationReconciler) checkHealth(ctx context.Context, func (r *KustomizationReconciler) prune(ctx context.Context, manager *ssa.ResourceManager, obj *kustomizev1.Kustomization, + src sourcev1.Source, revision string, originRevision string, objects []*unstructured.Unstructured) (bool, []*unstructured.Unstructured, error) { @@ -1122,7 +1133,7 @@ func (r *KustomizationReconciler) prune(ctx context.Context, // emit event only if the prune operation resulted in changes if changeSet != nil && len(changeSet.Entries) > 0 { log.Info(fmt.Sprintf("garbage collection completed: %s", changeSet.String())) - r.event(obj, revision, originRevision, eventv1.EventSeverityInfo, changeSet.String(), nil) + r.event(obj, src, revision, originRevision, eventv1.EventSeverityInfo, eventv1.ActionDeleted, changeSet.String(), nil) return true, nil, nil } @@ -1187,7 +1198,7 @@ func finalizerShouldDeleteResources(obj *kustomizev1.Kustomization) bool { // If the service account used for impersonation is no longer available or if a timeout occurs // while waiting for resources to be terminated, an error is logged and the finalizer is removed. func (r *KustomizationReconciler) finalize(ctx context.Context, - obj *kustomizev1.Kustomization) (ctrl.Result, error) { + obj *kustomizev1.Kustomization, src sourcev1.Source) (ctrl.Result, error) { log := ctrl.LoggerFrom(ctx) if finalizerShouldDeleteResources(obj) { objects, _ := inventory.List(obj.Status.Inventory) @@ -1228,14 +1239,16 @@ func (r *KustomizationReconciler) finalize(ctx context.Context, changeSet, err := deleteObjects(ctx, obj, resourceManager, objects) if err != nil { - r.event(obj, obj.Status.LastAppliedRevision, obj.Status.LastAppliedOriginRevision, eventv1.EventSeverityError, "pruning for deleted resource failed", nil) + r.event(obj, src, obj.Status.LastAppliedRevision, obj.Status.LastAppliedOriginRevision, + eventv1.EventSeverityError, eventv1.ActionFailed, "pruning for deleted resource failed", nil) // Return the error so we retry the failed garbage collection return ctrl.Result{}, err } if changeSet != nil && len(changeSet.Entries) > 0 { // Emit event with the resources marked for deletion. - r.event(obj, obj.Status.LastAppliedRevision, obj.Status.LastAppliedOriginRevision, eventv1.EventSeverityInfo, changeSet.String(), nil) + r.event(obj, src, obj.Status.LastAppliedRevision, obj.Status.LastAppliedOriginRevision, + eventv1.EventSeverityInfo, eventv1.ActionDeleted, changeSet.String(), nil) // Wait for the resources marked for deletion to be terminated. if obj.GetDeletionPolicy() == kustomizev1.DeletionPolicyWaitForTermination { @@ -1246,7 +1259,8 @@ func (r *KustomizationReconciler) finalize(ctx context.Context, // Emit an event and log the error if a timeout occurs. msg := "failed to wait for resources termination" log.Error(err, msg) - r.event(obj, obj.Status.LastAppliedRevision, obj.Status.LastAppliedOriginRevision, eventv1.EventSeverityError, msg, nil) + r.event(obj, src, obj.Status.LastAppliedRevision, obj.Status.LastAppliedOriginRevision, + eventv1.EventSeverityError, eventv1.ActionFailed, msg, nil) } } } @@ -1254,7 +1268,8 @@ func (r *KustomizationReconciler) finalize(ctx context.Context, // when the account to impersonate is gone, log the stale objects and continue with the finalization msg := fmt.Sprintf("unable to prune objects: \n%s", ssautil.FmtUnstructuredList(objects)) log.Error(fmt.Errorf("skiping pruning, failed to find account to impersonate"), msg) - r.event(obj, obj.Status.LastAppliedRevision, obj.Status.LastAppliedOriginRevision, eventv1.EventSeverityError, msg, nil) + r.event(obj, src, obj.Status.LastAppliedRevision, obj.Status.LastAppliedOriginRevision, + eventv1.EventSeverityError, eventv1.ActionFailed, msg, nil) } } @@ -1271,7 +1286,10 @@ func (r *KustomizationReconciler) finalize(ctx context.Context, } func (r *KustomizationReconciler) event(obj *kustomizev1.Kustomization, - revision, originRevision, severity, msg string, + src sourcev1.Source, + revision, originRevision, severity, + action string, + msg string, metadata map[string]string) { if metadata == nil { metadata = map[string]string{} @@ -1293,7 +1311,7 @@ func (r *KustomizationReconciler) event(obj *kustomizev1.Kustomization, eventType = corev1.EventTypeWarning } - r.EventRecorder.AnnotatedEventf(obj, metadata, eventType, reason, "%s", msg) + r.EventRecorder.AnnotatedEventf(obj, src, metadata, eventType, reason, action, "%s", msg) } func (r *KustomizationReconciler) finalizeStatus(ctx context.Context, diff --git a/internal/controller/kustomization_controller_test.go b/internal/controller/kustomization_controller_test.go index b3672abee..e1637522e 100644 --- a/internal/controller/kustomization_controller_test.go +++ b/internal/controller/kustomization_controller_test.go @@ -22,18 +22,18 @@ import ( "testing" "time" - "github.com/fluxcd/pkg/apis/meta" - sourcev1 "github.com/fluxcd/source-controller/api/v1" . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/tools/record" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1" + "github.com/fluxcd/pkg/apis/meta" + "github.com/fluxcd/pkg/runtime/events" + sourcev1 "github.com/fluxcd/source-controller/api/v1" ) func TestKustomizationReconciler_StagedApply(t *testing.T) { @@ -130,7 +130,7 @@ func TestKustomizationReconciler_deleteBeforeFinalizer(t *testing.T) { r := &KustomizationReconciler{ Client: k8sClient, - EventRecorder: record.NewFakeRecorder(32), + EventRecorder: events.NewFakeRecorder(32, true), } // NOTE: Only a real API server responds with an error in this scenario. _, err := r.Reconcile(ctx, ctrl.Request{NamespacedName: client.ObjectKeyFromObject(kustomization)}) diff --git a/internal/controller/kustomization_decryptor_test.go b/internal/controller/kustomization_decryptor_test.go index d4cdb91c3..0d80a9cca 100644 --- a/internal/controller/kustomization_decryptor_test.go +++ b/internal/controller/kustomization_decryptor_test.go @@ -24,8 +24,6 @@ import ( "testing" "time" - "github.com/fluxcd/pkg/apis/meta" - sourcev1 "github.com/fluxcd/source-controller/api/v1" "github.com/hashicorp/vault/api" . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" @@ -33,6 +31,10 @@ import ( "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" + "github.com/fluxcd/pkg/apis/meta" + "github.com/fluxcd/pkg/runtime/testenv" + sourcev1 "github.com/fluxcd/source-controller/api/v1" + kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1" ) @@ -193,10 +195,10 @@ func TestKustomizationReconciler_Decryptor(t *testing.T) { return resultK.Status.LastAppliedRevision == revision }, timeout, time.Second).Should(BeTrue()) - events := getEvents(resultK.GetName(), map[string]string{"kustomize.toolkit.fluxcd.io/revision": revision}) + events, _ := testenv.GetEvents(ctx, k8sClient, resultK.GetName(), "", map[string]string{"kustomize.toolkit.fluxcd.io/revision": revision}) g.Expect(len(events)).To(BeIdenticalTo(1)) - g.Expect(events[0].Message).Should(ContainSubstring("Reconciliation finished")) - g.Expect(events[0].Message).ShouldNot(ContainSubstring("configured")) + g.Expect(events[0].Note).Should(ContainSubstring("Reconciliation finished")) + g.Expect(events[0].Note).ShouldNot(ContainSubstring("configured")) }) t.Run("global SOPS age secret as fallback", func(t *testing.T) { diff --git a/internal/controller/kustomization_externalartifact_test.go b/internal/controller/kustomization_externalartifact_test.go index dedd8a502..8b4168d8a 100644 --- a/internal/controller/kustomization_externalartifact_test.go +++ b/internal/controller/kustomization_externalartifact_test.go @@ -24,10 +24,6 @@ import ( "testing" "time" - apiacl "github.com/fluxcd/pkg/apis/acl" - "github.com/fluxcd/pkg/apis/meta" - "github.com/fluxcd/pkg/testserver" - sourcev1 "github.com/fluxcd/source-controller/api/v1" . "github.com/onsi/gomega" "github.com/opencontainers/go-digest" apimeta "k8s.io/apimachinery/pkg/api/meta" @@ -35,6 +31,12 @@ import ( "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" + apiacl "github.com/fluxcd/pkg/apis/acl" + "github.com/fluxcd/pkg/apis/meta" + "github.com/fluxcd/pkg/runtime/testenv" + "github.com/fluxcd/pkg/testserver" + sourcev1 "github.com/fluxcd/source-controller/api/v1" + kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1" ) @@ -119,14 +121,14 @@ stringData: g.Expect(readyCondition.Reason).To(Equal(meta.ReconciliationSucceededReason)) g.Expect(resultK.Status.LastAppliedRevision).To(Equal(revision)) - events := getEvents(resultK.GetName(), map[string]string{"kustomize.toolkit.fluxcd.io/revision": revision}) + events, _ := testenv.GetEvents(ctx, k8sClient, resultK.GetName(), "", map[string]string{"kustomize.toolkit.fluxcd.io/revision": revision}) g.Expect(len(events) > 2).To(BeTrue()) g.Expect(events[0].Reason).To(BeIdenticalTo(meta.ProgressingReason)) - g.Expect(events[0].Message).To(ContainSubstring("created")) + g.Expect(events[0].Note).To(ContainSubstring("created")) g.Expect(events[1].Reason).To(BeIdenticalTo(meta.ProgressingReason)) - g.Expect(events[1].Message).To(ContainSubstring("check passed")) + g.Expect(events[1].Note).To(ContainSubstring("check passed")) g.Expect(events[2].Reason).To(BeIdenticalTo(meta.ReconciliationSucceededReason)) - g.Expect(events[2].Message).To(ContainSubstring("finished")) + g.Expect(events[2].Note).To(ContainSubstring("finished")) }) t.Run("watches for external artifact revision change", func(t *testing.T) { @@ -162,9 +164,9 @@ stringData: g.Expect(readyCondition.Reason).To(Equal(apiacl.AccessDeniedReason)) g.Expect(apimeta.IsStatusConditionTrue(resultK.Status.Conditions, meta.StalledCondition)).Should(BeTrue()) - events := getEvents(resultK.GetName(), nil) + events, _ := testenv.GetEvents(ctx, k8sClient, resultK.GetName(), "", nil) g.Expect(events[len(events)-1].Reason).To(BeIdenticalTo(apiacl.AccessDeniedReason)) - g.Expect(events[len(events)-1].Message).To(ContainSubstring("feature gate is disabled")) + g.Expect(events[len(events)-1].Note).To(ContainSubstring("feature gate is disabled")) }) } diff --git a/internal/controller/kustomization_force_test.go b/internal/controller/kustomization_force_test.go index 7d8654cc8..85d97b498 100644 --- a/internal/controller/kustomization_force_test.go +++ b/internal/controller/kustomization_force_test.go @@ -22,9 +22,6 @@ import ( "testing" "time" - "github.com/fluxcd/pkg/apis/meta" - "github.com/fluxcd/pkg/testserver" - sourcev1 "github.com/fluxcd/source-controller/api/v1" . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" apimeta "k8s.io/apimachinery/pkg/api/meta" @@ -32,6 +29,11 @@ import ( "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" + "github.com/fluxcd/pkg/apis/meta" + "github.com/fluxcd/pkg/runtime/testenv" + "github.com/fluxcd/pkg/testserver" + sourcev1 "github.com/fluxcd/source-controller/api/v1" + kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1" ) @@ -141,10 +143,10 @@ stringData: kstatusCheck.CheckErr(ctx, resultK) t.Run("emits validation error event", func(t *testing.T) { - events := getEvents(resultK.GetName(), map[string]string{"kustomize.toolkit.fluxcd.io/revision": revision}) + events, _ := testenv.GetEvents(ctx, k8sClient, resultK.GetName(), "", map[string]string{"kustomize.toolkit.fluxcd.io/revision": revision}) g.Expect(len(events) > 0).To(BeTrue()) g.Expect(events[0].Type).To(BeIdenticalTo("Warning")) - g.Expect(events[0].Message).To(ContainSubstring("field is immutable")) + g.Expect(events[0].Note).To(ContainSubstring("field is immutable")) }) }) diff --git a/internal/controller/kustomization_fuzzer_test.go b/internal/controller/kustomization_fuzzer_test.go index 2404b5ef9..5147a5609 100644 --- a/internal/controller/kustomization_fuzzer_test.go +++ b/internal/controller/kustomization_fuzzer_test.go @@ -43,6 +43,7 @@ import ( "github.com/opencontainers/go-digest" "github.com/ory/dockertest/v3" corev1 "k8s.io/api/core/v1" + eventsv1 "k8s.io/api/events/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" utilruntime "k8s.io/apimachinery/pkg/util/runtime" @@ -529,12 +530,12 @@ func runInContext(registerControllers func(*testenv.Environment), run func() err runErr := run() if debugMode { - events := &corev1.EventList{} + events := &eventsv1.EventList{} _ = k8sClient.List(ctx, events) for _, event := range events.Items { fmt.Printf("%s %s \n%s\n", - event.InvolvedObject.Name, event.GetAnnotations()["kustomize.toolkit.fluxcd.io/revision"], - event.Message) + event.Regarding.Name, event.GetAnnotations()["kustomize.toolkit.fluxcd.io/revision"], + event.Note) } } @@ -562,27 +563,6 @@ func randStringRunes(n int) string { return string(b) } -func getEvents(objName string, annotations map[string]string) []corev1.Event { - var result []corev1.Event - events := &corev1.EventList{} - _ = k8sClient.List(ctx, events) - for _, event := range events.Items { - if event.InvolvedObject.Name == objName { - if annotations == nil && len(annotations) == 0 { - result = append(result, event) - } else { - for ak, av := range annotations { - if event.GetAnnotations()[ak] == av { - result = append(result, event) - break - } - } - } - } - } - return result -} - func applyGitRepository(objKey client.ObjectKey, artifactName string, revision string) error { repo := &sourcev1.GitRepository{ TypeMeta: metav1.TypeMeta{ diff --git a/internal/controller/kustomization_origin_revision_test.go b/internal/controller/kustomization_origin_revision_test.go index 5307f69f4..9f825ae97 100644 --- a/internal/controller/kustomization_origin_revision_test.go +++ b/internal/controller/kustomization_origin_revision_test.go @@ -22,16 +22,18 @@ import ( "testing" "time" - eventv1 "github.com/fluxcd/pkg/apis/event/v1beta1" - "github.com/fluxcd/pkg/apis/meta" - "github.com/fluxcd/pkg/testserver" - sourcev1 "github.com/fluxcd/source-controller/api/v1" . "github.com/onsi/gomega" apimeta "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" + eventv1 "github.com/fluxcd/pkg/apis/event/v1" + "github.com/fluxcd/pkg/apis/meta" + "github.com/fluxcd/pkg/runtime/testenv" + "github.com/fluxcd/pkg/testserver" + sourcev1 "github.com/fluxcd/source-controller/api/v1" + kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1" ) @@ -124,7 +126,7 @@ stringData: g.Expect(resultK.Status.History[0].LastReconciledDuration.Duration).To(BeNumerically(">", 0)) g.Expect(resultK.Status.History[0].Metadata).To(ContainElements(revision, "orev")) - events := getEvents(kustomizationKey.Name, nil) + events, _ := testenv.GetEvents(ctx, k8sClient, kustomizationKey.Name, "", nil) g.Expect(events).To(Not(BeEmpty())) annotationKey := kustomizev1.GroupVersion.Group + "/" + eventv1.MetaOriginRevisionKey diff --git a/internal/controller/kustomization_wait_test.go b/internal/controller/kustomization_wait_test.go index fa8813799..ac65a2d1a 100644 --- a/internal/controller/kustomization_wait_test.go +++ b/internal/controller/kustomization_wait_test.go @@ -22,9 +22,8 @@ import ( "testing" "time" - runtimeClient "github.com/fluxcd/pkg/runtime/client" . "github.com/onsi/gomega" - corev1 "k8s.io/api/core/v1" + eventsv1 "k8s.io/api/events/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -35,7 +34,9 @@ import ( "github.com/fluxcd/pkg/apis/kustomize" "github.com/fluxcd/pkg/apis/meta" + runtimeClient "github.com/fluxcd/pkg/runtime/client" "github.com/fluxcd/pkg/runtime/conditions" + "github.com/fluxcd/pkg/runtime/testenv" "github.com/fluxcd/pkg/testserver" sourcev1 "github.com/fluxcd/source-controller/api/v1" @@ -207,10 +208,10 @@ parameters: }) t.Run("emits unhealthy event", func(t *testing.T) { - events := getEvents(resultK.GetName(), map[string]string{"kustomize.toolkit.fluxcd.io/revision": revision}) + events, _ := testenv.GetEvents(ctx, k8sClient, resultK.GetName(), "", map[string]string{"kustomize.toolkit.fluxcd.io/revision": revision}) g.Expect(len(events) > 0).To(BeTrue()) g.Expect(events[len(events)-1].Type).To(BeIdenticalTo("Warning")) - g.Expect(events[len(events)-1].Message).To(ContainSubstring("does-not-exists")) + g.Expect(events[len(events)-1].Note).To(ContainSubstring("does-not-exists")) }) t.Run("recovers and reports healthy status", func(t *testing.T) { @@ -248,11 +249,12 @@ parameters: }) t.Run("emits recovery event", func(t *testing.T) { + g := NewWithT(t) expectedMessage := "Health check passed" - events := getEvents(resultK.GetName(), map[string]string{"kustomize.toolkit.fluxcd.io/revision": revision}) + events, _ := testenv.GetEvents(ctx, k8sClient, resultK.GetName(), "", map[string]string{"kustomize.toolkit.fluxcd.io/revision": revision}) g.Expect(len(events) > 1).To(BeTrue()) g.Expect(events[len(events)-2].Type).To(BeIdenticalTo("Normal")) - g.Expect(events[len(events)-2].Message).To(ContainSubstring(expectedMessage)) + g.Expect(events[len(events)-2].Note).To(ContainSubstring(expectedMessage)) }) t.Run("reports new revision healthy status", func(t *testing.T) { @@ -284,10 +286,10 @@ parameters: t.Run("emits event for the new revision", func(t *testing.T) { expectedMessage := "Health check passed" - events := getEvents(resultK.GetName(), map[string]string{"kustomize.toolkit.fluxcd.io/revision": revision}) + events, _ := testenv.GetEvents(ctx, k8sClient, resultK.GetName(), "", map[string]string{"kustomize.toolkit.fluxcd.io/revision": revision}) g.Expect(len(events) > 1).To(BeTrue()) g.Expect(events[len(events)-2].Type).To(BeIdenticalTo("Normal")) - g.Expect(events[len(events)-2].Message).To(ContainSubstring(expectedMessage)) + g.Expect(events[len(events)-2].Note).To(ContainSubstring(expectedMessage)) }) t.Run("finalizes object", func(t *testing.T) { @@ -746,10 +748,10 @@ spec: // Verify the HealthCheckCanceled event was emitted. g.Eventually(func() bool { - events := getEvents(resultK.GetName(), nil) + events, _ := testenv.GetEvents(ctx, k8sClient, resultK.GetName(), "", nil) for _, event := range events { if event.Reason == meta.HealthCheckCanceledReason { - t.Logf("Found HealthCheckCanceled event: %s", event.Message) + t.Logf("Found HealthCheckCanceled event: %s", event.Note) return true } } @@ -757,8 +759,8 @@ spec: }, timeout, time.Second).Should(BeTrue(), "HealthCheckCanceled event should be recorded") // Verify the event message indicates the trigger source. - events := getEvents(resultK.GetName(), nil) - var cancelEvent *corev1.Event + events, _ := testenv.GetEvents(ctx, k8sClient, resultK.GetName(), "", nil) + var cancelEvent *eventsv1.Event for i := range events { if events[i].Reason == meta.HealthCheckCanceledReason { cancelEvent = &events[i] @@ -766,8 +768,8 @@ spec: } } g.Expect(cancelEvent).ToNot(BeNil()) - g.Expect(cancelEvent.Message).To(ContainSubstring("Health checks canceled")) - g.Expect(cancelEvent.Message).To(ContainSubstring("GitRepository")) + g.Expect(cancelEvent.Note).To(ContainSubstring("Health checks canceled")) + g.Expect(cancelEvent.Note).To(ContainSubstring("GitRepository")) } func TestKustomizationReconciler_HealthCheckExprs_GroupOnly(t *testing.T) { diff --git a/internal/controller/suite_test.go b/internal/controller/suite_test.go index a0e0eead5..62b703aca 100644 --- a/internal/controller/suite_test.go +++ b/internal/controller/suite_test.go @@ -29,6 +29,7 @@ import ( "github.com/opencontainers/go-digest" "github.com/ory/dockertest/v3" corev1 "k8s.io/api/core/v1" + eventsv1 "k8s.io/api/events/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" utilruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/client-go/kubernetes/scheme" @@ -44,6 +45,7 @@ import ( "github.com/fluxcd/pkg/runtime/conditions" kcheck "github.com/fluxcd/pkg/runtime/conditions/check" "github.com/fluxcd/pkg/runtime/controller" + "github.com/fluxcd/pkg/runtime/events" "github.com/fluxcd/pkg/runtime/metrics" "github.com/fluxcd/pkg/runtime/testenv" "github.com/fluxcd/pkg/testserver" @@ -136,12 +138,12 @@ func runInContext(registerControllers func(*testenv.Environment), run func() int code = run() if debugMode { - events := &corev1.EventList{} + events := &eventsv1.EventList{} _ = k8sClient.List(ctx, events) for _, event := range events.Items { fmt.Printf("%s %s \n%s\n", - event.InvolvedObject.Name, event.GetAnnotations()["kustomize.toolkit.fluxcd.io/revision"], - event.Message) + event.Regarding.Name, event.GetAnnotations()["kustomize.toolkit.fluxcd.io/revision"], + event.Note) } } @@ -179,7 +181,7 @@ func TestMain(m *testing.M) { Client: testEnv, Mapper: testEnv.GetRESTMapper(), APIReader: testEnv, - EventRecorder: testEnv.GetEventRecorderFor(controllerName), + EventRecorder: createMockEventRecorder(testEnv, controllerName), Metrics: testMetricsH, DependencyRequeueInterval: 2 * time.Second, ConcurrentSSA: 4, @@ -198,6 +200,15 @@ func TestMain(m *testing.M) { os.Exit(code) } +func createMockEventRecorder(testEnv *testenv.Environment, controllerName string) events.Recorder { + logger := ctrl.Log.WithName("events") + eventRecorder, err := events.NewRecorder(logger, "", controllerName, events.WithManager(testEnv)) + if err != nil { + panic(fmt.Sprintf("Failed to create event recorder: %v", err)) + } + return eventRecorder +} + var letterRunes = []rune("abcdefghijklmnopqrstuvwxyz1234567890") func randStringRunes(n int) string { @@ -241,27 +252,6 @@ func logStatus(t *testing.T, k *kustomizev1.Kustomization) { t.Log(string(sts)) } -func getEvents(objName string, annotations map[string]string) []corev1.Event { - var result []corev1.Event - events := &corev1.EventList{} - _ = k8sClient.List(ctx, events) - for _, event := range events.Items { - if event.InvolvedObject.Name == objName { - if annotations == nil && len(annotations) == 0 { - result = append(result, event) - } else { - for ak, av := range annotations { - if event.GetAnnotations()[ak] == av { - result = append(result, event) - break - } - } - } - } - } - return result -} - func createNamespace(name string) error { namespace := &corev1.Namespace{ ObjectMeta: metav1.ObjectMeta{Name: name}, diff --git a/main.go b/main.go index 0aff4672b..41b929581 100644 --- a/main.go +++ b/main.go @@ -252,8 +252,8 @@ func main() { probes.SetupChecks(mgr, setupLog) - var eventRecorder *events.Recorder - if eventRecorder, err = events.NewRecorder(mgr, ctrl.Log, eventsAddr, controllerName); err != nil { + eventRecorder, err := events.NewRecorder(ctrl.Log, eventsAddr, controllerName, events.WithManager(mgr)) + if err != nil { setupLog.Error(err, "unable to create event recorder") os.Exit(1) }