From 960380bc86cc6ba8839ef7e762b2f327a9fe8d03 Mon Sep 17 00:00:00 2001 From: Mike Beaumont Date: Tue, 21 May 2024 17:25:56 +0200 Subject: [PATCH] feat(MeshService): add events when generating from Kubernetes Service (#10290) Also sets `k8s.kuma.io/service-name` Signed-off-by: Mike Beaumont --- .../k8s/controllers/meshservice_controller.go | 36 ++++++++++++++++--- .../meshservice_controller_test.go | 8 +++-- .../testdata/meshservice/01.meshservice.yaml | 1 + .../runtime/k8s/metadata/annotations.go | 3 ++ pkg/plugins/runtime/k8s/plugin.go | 7 ++-- 5 files changed, 45 insertions(+), 10 deletions(-) diff --git a/pkg/plugins/runtime/k8s/controllers/meshservice_controller.go b/pkg/plugins/runtime/k8s/controllers/meshservice_controller.go index 907536ec0aae..c85da58a7538 100644 --- a/pkg/plugins/runtime/k8s/controllers/meshservice_controller.go +++ b/pkg/plugins/runtime/k8s/controllers/meshservice_controller.go @@ -11,6 +11,7 @@ import ( v1 "k8s.io/apimachinery/pkg/apis/meta/v1" kube_runtime "k8s.io/apimachinery/pkg/runtime" kube_types "k8s.io/apimachinery/pkg/types" + kube_record "k8s.io/client-go/tools/record" kube_ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/builder" kube_client "sigs.k8s.io/controller-runtime/pkg/client" @@ -30,9 +31,22 @@ import ( "github.com/kumahq/kuma/pkg/util/pointer" ) +const ( + // CreatedMeshServiceReason is added to an event when + // a new MeshService is successfully created. + CreatedMeshServiceReason = "CreatedMeshService" + // UpdatedMeshServiceReason is added to an event when + // an existing MeshService is successfully updated. + UpdatedMeshServiceReason = "UpdatedMeshService" + // FailedToGenerateMeshServiceReason is added to an event when + // a MeshService cannot be generated. + FailedToGenerateMeshServiceReason = "FailedToGenerateMeshService" +) + // MeshServiceReconciler reconciles a MeshService object type MeshServiceReconciler struct { kube_client.Client + kube_record.EventRecorder Log logr.Logger Scheme *kube_runtime.Scheme } @@ -101,16 +115,22 @@ func (r *MeshServiceReconciler) Reconcile(ctx context.Context, req kube_ctrl.Req Namespace: svc.GetNamespace(), }, } - if err := kube_controllerutil.SetOwnerReference(svc, ms, r.Scheme); err != nil { - return kube_ctrl.Result{}, errors.Wrap(err, "could not set owner reference") - } operationResult, err := kube_controllerutil.CreateOrUpdate(ctx, r.Client, ms, func() error { + if ms.ObjectMeta.GetGeneration() != 0 { + if owners := ms.GetOwnerReferences(); len(owners) == 0 || owners[0].UID != svc.GetUID() { + r.EventRecorder.Eventf( + svc, kube_core.EventTypeWarning, FailedToGenerateMeshServiceReason, "MeshService already exists and isn't owned by Service", + ) + return errors.Errorf("MeshService already exists and isn't owned by Service") + } + } ms.ObjectMeta.Labels = maps.Clone(svc.GetLabels()) if ms.ObjectMeta.Labels == nil { ms.ObjectMeta.Labels = map[string]string{} } ms.ObjectMeta.Labels[mesh_proto.MeshTag] = mesh + ms.ObjectMeta.Labels[metadata.KumaSerivceName] = svc.GetName() if ms.Spec == nil { ms.Spec = &meshservice_api.MeshService{} } @@ -139,12 +159,20 @@ func (r *MeshServiceReconciler) Reconcile(ctx context.Context, req kube_ctrl.Req IP: svc.Spec.ClusterIP, }, } + if err := kube_controllerutil.SetOwnerReference(svc, ms, r.Scheme); err != nil { + return errors.Wrap(err, "could not set owner reference") + } return nil }) if err != nil { return kube_ctrl.Result{}, err } - + switch operationResult { + case kube_controllerutil.OperationResultCreated: + r.EventRecorder.Eventf(svc, kube_core.EventTypeNormal, CreatedMeshServiceReason, "Created Kuma MeshService: %s", ms.Name) + case kube_controllerutil.OperationResultUpdated: + r.EventRecorder.Eventf(svc, kube_core.EventTypeNormal, UpdatedMeshServiceReason, "Updated Kuma MeshService: %s", ms.Name) + } log.V(1).Info("mesh service reconciled", "result", operationResult) return kube_ctrl.Result{}, nil } diff --git a/pkg/plugins/runtime/k8s/controllers/meshservice_controller_test.go b/pkg/plugins/runtime/k8s/controllers/meshservice_controller_test.go index a8730d86f739..80d51398a841 100644 --- a/pkg/plugins/runtime/k8s/controllers/meshservice_controller_test.go +++ b/pkg/plugins/runtime/k8s/controllers/meshservice_controller_test.go @@ -12,6 +12,7 @@ import ( kube_core "k8s.io/api/core/v1" kube_errors "k8s.io/apimachinery/pkg/api/errors" kube_types "k8s.io/apimachinery/pkg/types" + kube_record "k8s.io/client-go/tools/record" kube_ctrl "sigs.k8s.io/controller-runtime" kube_client "sigs.k8s.io/controller-runtime/pkg/client" kube_client_fake "sigs.k8s.io/controller-runtime/pkg/client/fake" @@ -62,9 +63,10 @@ var _ = Describe("MeshServiceController", func() { Build() reconciler = &MeshServiceReconciler{ - Client: kubeClient, - Log: logr.Discard(), - Scheme: k8sClientScheme, + Client: kubeClient, + Log: logr.Discard(), + Scheme: k8sClientScheme, + EventRecorder: kube_record.NewFakeRecorder(10), } key := kube_types.NamespacedName{ diff --git a/pkg/plugins/runtime/k8s/controllers/testdata/meshservice/01.meshservice.yaml b/pkg/plugins/runtime/k8s/controllers/testdata/meshservice/01.meshservice.yaml index e4a0b630f4d9..ed5daed00cf4 100644 --- a/pkg/plugins/runtime/k8s/controllers/testdata/meshservice/01.meshservice.yaml +++ b/pkg/plugins/runtime/k8s/controllers/testdata/meshservice/01.meshservice.yaml @@ -1,6 +1,7 @@ metadata: creationTimestamp: null labels: + k8s.kuma.io/service-name: example kuma.io/mesh: default name: example namespace: demo diff --git a/pkg/plugins/runtime/k8s/metadata/annotations.go b/pkg/plugins/runtime/k8s/metadata/annotations.go index deab1abf39fa..fb457269ec2c 100644 --- a/pkg/plugins/runtime/k8s/metadata/annotations.go +++ b/pkg/plugins/runtime/k8s/metadata/annotations.go @@ -115,6 +115,9 @@ const ( KumaInitFirst = "kuma.io/init-first" // KumaWaitForDataplaneReady allows to specify if the application sidecar should be hold until Envoy is ready KumaWaitForDataplaneReady = "kuma.io/wait-for-dataplane-ready" + + // KumaServiceName points to the Service that a MeshService is derived from + KumaSerivceName = "k8s.kuma.io/service-name" ) var PodAnnotationDeprecations = []Deprecation{ diff --git a/pkg/plugins/runtime/k8s/plugin.go b/pkg/plugins/runtime/k8s/plugin.go index 3599289ad6d5..405a3d6010bb 100644 --- a/pkg/plugins/runtime/k8s/plugin.go +++ b/pkg/plugins/runtime/k8s/plugin.go @@ -142,9 +142,10 @@ func addServiceReconciler(mgr kube_ctrl.Manager) error { func addMeshServiceReconciler(mgr kube_ctrl.Manager) error { reconciler := &k8s_controllers.MeshServiceReconciler{ - Client: mgr.GetClient(), - Log: core.Log.WithName("controllers").WithName("MeshService"), - Scheme: mgr.GetScheme(), + Client: mgr.GetClient(), + Log: core.Log.WithName("controllers").WithName("MeshService"), + Scheme: mgr.GetScheme(), + EventRecorder: mgr.GetEventRecorderFor("k8s.kuma.io/mesh-service-generator"), } return reconciler.SetupWithManager(mgr) }