From 3dd7ed55e330a433e19662717afdb90aa6c21bd6 Mon Sep 17 00:00:00 2001 From: Mike Dame Date: Fri, 20 Dec 2024 13:26:27 -0500 Subject: [PATCH 01/12] Add SourceReconciler and create InstrumentationConfig --- .../controllers/startlangdetection/manager.go | 16 +++++++++- .../startlangdetection/source_controller.go | 31 +++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 instrumentor/controllers/startlangdetection/source_controller.go diff --git a/instrumentor/controllers/startlangdetection/manager.go b/instrumentor/controllers/startlangdetection/manager.go index 2be2646cd..0528db3ae 100644 --- a/instrumentor/controllers/startlangdetection/manager.go +++ b/instrumentor/controllers/startlangdetection/manager.go @@ -1,12 +1,14 @@ package startlangdetection import ( - odigospredicate "github.com/odigos-io/odigos/k8sutils/pkg/predicate" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/builder" "sigs.k8s.io/controller-runtime/pkg/predicate" + + "github.com/odigos-io/odigos/api/odigos/v1alpha1" + odigospredicate "github.com/odigos-io/odigos/k8sutils/pkg/predicate" ) func SetupWithManager(mgr ctrl.Manager) error { @@ -74,5 +76,17 @@ func SetupWithManager(mgr ctrl.Manager) error { return err } + err = builder. + ControllerManagedBy(mgr). + Named("startlangdetection-source"). + For(&v1alpha1.Source{}). + Complete(&SourceReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + }) + if err != nil { + return err + } + return nil } diff --git a/instrumentor/controllers/startlangdetection/source_controller.go b/instrumentor/controllers/startlangdetection/source_controller.go new file mode 100644 index 000000000..b0f907144 --- /dev/null +++ b/instrumentor/controllers/startlangdetection/source_controller.go @@ -0,0 +1,31 @@ +package startlangdetection + +import ( + "context" + + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/odigos-io/odigos/api/odigos/v1alpha1" + "github.com/odigos-io/odigos/k8sutils/pkg/workload" +) + +type SourceReconciler struct { + client.Client + Scheme *runtime.Scheme +} + +func (s *SourceReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + var source v1alpha1.Source + err := s.Get(ctx, req.NamespacedName, &source) + if err != nil { + return ctrl.Result{}, client.IgnoreNotFound(err) + } + + instConfigName := workload.CalculateWorkloadRuntimeObjectName(req.Name, source.Spec.Workload.Kind) + obj := workload.ClientObjectFromWorkloadKind(source.Spec.Workload.Kind) + + err = requestOdigletsToCalculateRuntimeDetails(ctx, s.Client, instConfigName, req.Namespace, obj, s.Scheme) + return ctrl.Result{}, err +} From dae2bd9e0447201ceca2624837930ea09adbccee Mon Sep 17 00:00:00 2001 From: Mike Dame Date: Fri, 20 Dec 2024 13:37:02 -0500 Subject: [PATCH 02/12] Add finalizer for uninstrumentation --- .../startlangdetection/source_controller.go | 39 ++++++++++++++++--- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/instrumentor/controllers/startlangdetection/source_controller.go b/instrumentor/controllers/startlangdetection/source_controller.go index b0f907144..fc742bdaa 100644 --- a/instrumentor/controllers/startlangdetection/source_controller.go +++ b/instrumentor/controllers/startlangdetection/source_controller.go @@ -6,26 +6,55 @@ import ( "k8s.io/apimachinery/pkg/runtime" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" "github.com/odigos-io/odigos/api/odigos/v1alpha1" "github.com/odigos-io/odigos/k8sutils/pkg/workload" ) +var sourceFinalizer = "odigos.io/source-finalizer" + type SourceReconciler struct { client.Client Scheme *runtime.Scheme } -func (s *SourceReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - var source v1alpha1.Source - err := s.Get(ctx, req.NamespacedName, &source) +func (r *SourceReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + source := &v1alpha1.Source{} + err := r.Get(ctx, req.NamespacedName, source) if err != nil { return ctrl.Result{}, client.IgnoreNotFound(err) } - instConfigName := workload.CalculateWorkloadRuntimeObjectName(req.Name, source.Spec.Workload.Kind) obj := workload.ClientObjectFromWorkloadKind(source.Spec.Workload.Kind) + err = r.Client.Get(ctx, types.NamespacedName{Name: source.Spec.Workload.Name, Namespace: source.Spec.Workload.Namespace}, obj) + if err != nil { + // Deleted objects should be filtered in the event filter + return ctrl.Result{}, err + } + + if source.DeletionTimestamp.IsZero() { + if !controllerutil.ContainsFinalizer(source, sourceFinalizer) { + controllerutil.AddFinalizer(source, sourceFinalizer) + if err := r.Update(ctx, source); err != nil { + return ctrl.Result{}, err + } + + instConfigName := workload.CalculateWorkloadRuntimeObjectName(req.Name, source.Spec.Workload.Kind) + err = requestOdigletsToCalculateRuntimeDetails(ctx, r.Client, instConfigName, req.Namespace, obj, r.Scheme) + return ctrl.Result{}, err + } + } else { + // Source is being deleted + if controllerutil.ContainsFinalizer(source, sourceFinalizer) { + // TODO: delete resources + + controllerutil.RemoveFinalizer(source, sourceFinalizer) + if err := r.Update(ctx, source); err != nil { + return ctrl.Result{}, err + } + } + } - err = requestOdigletsToCalculateRuntimeDetails(ctx, s.Client, instConfigName, req.Namespace, obj, s.Scheme) return ctrl.Result{}, err } From 9ba9b57f614d233f81ccc0d7d173c10076714223 Mon Sep 17 00:00:00 2001 From: Mike Dame Date: Fri, 20 Dec 2024 13:48:46 -0500 Subject: [PATCH 03/12] Delete InstrumentationConfig and remove Finalizer when Source is deleted --- .../startlangdetection/source_controller.go | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/instrumentor/controllers/startlangdetection/source_controller.go b/instrumentor/controllers/startlangdetection/source_controller.go index fc742bdaa..fa292dc0c 100644 --- a/instrumentor/controllers/startlangdetection/source_controller.go +++ b/instrumentor/controllers/startlangdetection/source_controller.go @@ -4,6 +4,7 @@ import ( "context" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" @@ -29,9 +30,10 @@ func (r *SourceReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctr obj := workload.ClientObjectFromWorkloadKind(source.Spec.Workload.Kind) err = r.Client.Get(ctx, types.NamespacedName{Name: source.Spec.Workload.Name, Namespace: source.Spec.Workload.Namespace}, obj) if err != nil { - // Deleted objects should be filtered in the event filter + // TODO: Deleted objects should be filtered in the event filter return ctrl.Result{}, err } + instConfigName := workload.CalculateWorkloadRuntimeObjectName(source.Spec.Workload.Name, source.Spec.Workload.Kind) if source.DeletionTimestamp.IsZero() { if !controllerutil.ContainsFinalizer(source, sourceFinalizer) { @@ -40,19 +42,29 @@ func (r *SourceReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctr return ctrl.Result{}, err } - instConfigName := workload.CalculateWorkloadRuntimeObjectName(req.Name, source.Spec.Workload.Kind) err = requestOdigletsToCalculateRuntimeDetails(ctx, r.Client, instConfigName, req.Namespace, obj, r.Scheme) return ctrl.Result{}, err } } else { // Source is being deleted if controllerutil.ContainsFinalizer(source, sourceFinalizer) { - // TODO: delete resources - + // Remove the finalizer first, because if the InstrumentationConfig is not found we + // will deadlock on the finalizer never getting removed. + // On the other hand, this could end up deleting a Source with an orphaned InstrumentationConfig. controllerutil.RemoveFinalizer(source, sourceFinalizer) if err := r.Update(ctx, source); err != nil { return ctrl.Result{}, err } + + instConfig := &v1alpha1.InstrumentationConfig{} + err = r.Client.Get(ctx, types.NamespacedName{Name: instConfigName, Namespace: req.Namespace}, instConfig) + if err != nil { + return ctrl.Result{}, client.IgnoreNotFound(err) + } + err = r.Client.Delete(ctx, instConfig) + if err != nil { + return ctrl.Result{}, client.IgnoreNotFound(err) + } } } From df8cc4f672b7ca7a9938fe96439c1ccc693c0aa7 Mon Sep 17 00:00:00 2001 From: Mike Dame Date: Fri, 20 Dec 2024 13:52:32 -0500 Subject: [PATCH 04/12] Add Sources to Instrumentor ClusterRole --- cli/cmd/resources/instrumentor.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/cli/cmd/resources/instrumentor.go b/cli/cmd/resources/instrumentor.go index 89e3c7d8e..ef6c68fda 100644 --- a/cli/cmd/resources/instrumentor.go +++ b/cli/cmd/resources/instrumentor.go @@ -191,6 +191,16 @@ func NewInstrumentorClusterRole() *rbacv1.ClusterRole { Resources: []string{"instrumentationconfigs"}, Verbs: []string{"create", "delete", "get", "list", "patch", "update", "watch"}, }, + { + APIGroups: []string{"odigos.io"}, + Resources: []string{"sources"}, + Verbs: []string{"create", "delete", "get", "list", "patch", "update", "watch"}, + }, + { + APIGroups: []string{"odigos.io"}, + Resources: []string{"sources/finalizers"}, + Verbs: []string{"update"}, + }, }, } } From 6bfeb1d8dc3dcc89220bcade9a30615e18bf12fc Mon Sep 17 00:00:00 2001 From: Mike Dame Date: Fri, 20 Dec 2024 14:11:24 -0500 Subject: [PATCH 05/12] Add workload labels to Source --- .../startlangdetection/source_controller.go | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/instrumentor/controllers/startlangdetection/source_controller.go b/instrumentor/controllers/startlangdetection/source_controller.go index fa292dc0c..855fa4ca6 100644 --- a/instrumentor/controllers/startlangdetection/source_controller.go +++ b/instrumentor/controllers/startlangdetection/source_controller.go @@ -13,7 +13,13 @@ import ( "github.com/odigos-io/odigos/k8sutils/pkg/workload" ) -var sourceFinalizer = "odigos.io/source-finalizer" +var ( + sourceFinalizer = "odigos.io/source-finalizer" + + workloadNameLabel = "odigos.io/workload-name" + workloadNamespaceLabel = "odigos.io/workload-namespace" + workloadKindLabel = "odigos.io/workload-kind" +) type SourceReconciler struct { client.Client @@ -38,6 +44,14 @@ func (r *SourceReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctr if source.DeletionTimestamp.IsZero() { if !controllerutil.ContainsFinalizer(source, sourceFinalizer) { controllerutil.AddFinalizer(source, sourceFinalizer) + + if source.Labels == nil { + source.Labels = make(map[string]string) + } + source.Labels[workloadNameLabel] = source.Spec.Workload.Name + source.Labels[workloadNamespaceLabel] = source.Spec.Workload.Namespace + source.Labels[workloadKindLabel] = string(source.Spec.Workload.Kind) + if err := r.Update(ctx, source); err != nil { return ctrl.Result{}, err } From 312854c1cb719329067156d9d93f1a3841b9019b Mon Sep 17 00:00:00 2001 From: Mike Dame Date: Fri, 20 Dec 2024 15:04:14 -0500 Subject: [PATCH 06/12] Update Uninstall command to delete Source finalizers --- Makefile | 7 ++++++- cli/cmd/uninstall.go | 14 ++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 06f564c9d..67d0afb4b 100644 --- a/Makefile +++ b/Makefile @@ -200,6 +200,11 @@ cli-install: @echo "Installing odigos from source. version: $(ODIGOS_CLI_VERSION)" cd ./cli ; go run -tags=embed_manifests . install --version $(ODIGOS_CLI_VERSION) +.PHONY: cli-uninstall +cli-uninstall: + @echo "Installing odigos from source. version: $(ODIGOS_CLI_VERSION)" + cd ./cli ; go run -tags=embed_manifests . uninstall + .PHONY: cli-upgrade cli-upgrade: @echo "Upgrading odigos from source. version: $(ODIGOS_CLI_VERSION)" @@ -255,4 +260,4 @@ dev-nop-destination: .PHONY: dev-add-backpressue-destination dev-backpressue-destination: - kubectl apply -f ./tests/backpressure-exporter.yaml \ No newline at end of file + kubectl apply -f ./tests/backpressure-exporter.yaml diff --git a/cli/cmd/uninstall.go b/cli/cmd/uninstall.go index c7998609f..608fa981f 100644 --- a/cli/cmd/uninstall.go +++ b/cli/cmd/uninstall.go @@ -387,6 +387,20 @@ func uninstallCRDs(ctx context.Context, cmd *cobra.Command, client *kube.Client, return err } + // Clear finalizers from Source objects so they can be uninstalled + sources, err := client.OdigosClient.Sources("").List(ctx, metav1.ListOptions{}) + for _, i := range sources.Items { + source, err := client.OdigosClient.Sources(i.Namespace).Get(ctx, i.Name, metav1.GetOptions{}) + if err != nil { + return err + } + source.SetFinalizers([]string{}) + _, err = client.OdigosClient.Sources(i.Namespace).Update(ctx, source, metav1.UpdateOptions{}) + if err != nil { + return err + } + } + for _, i := range list.Items { err = client.ApiExtensions.ApiextensionsV1().CustomResourceDefinitions().Delete(ctx, i.Name, metav1.DeleteOptions{}) if err != nil { From 9528b4b19686c9c9af30f3c7e92b4872ec8da6b5 Mon Sep 17 00:00:00 2001 From: Mike Dame Date: Fri, 20 Dec 2024 15:25:29 -0500 Subject: [PATCH 07/12] Add logger to SourceReconciler --- .../controllers/startlangdetection/source_controller.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/instrumentor/controllers/startlangdetection/source_controller.go b/instrumentor/controllers/startlangdetection/source_controller.go index 855fa4ca6..6c8c510dd 100644 --- a/instrumentor/controllers/startlangdetection/source_controller.go +++ b/instrumentor/controllers/startlangdetection/source_controller.go @@ -8,6 +8,7 @@ import ( ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "sigs.k8s.io/controller-runtime/pkg/log" "github.com/odigos-io/odigos/api/odigos/v1alpha1" "github.com/odigos-io/odigos/k8sutils/pkg/workload" @@ -27,6 +28,8 @@ type SourceReconciler struct { } func (r *SourceReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + logger := log.FromContext(ctx) + logger.Info("Reconciling Source object", "name", req.Name, "namespace", req.Namespace) source := &v1alpha1.Source{} err := r.Get(ctx, req.NamespacedName, source) if err != nil { From 378d0bf4b741e4482be74b9eececef2fb7620b3f Mon Sep 17 00:00:00 2001 From: Mike Dame Date: Fri, 20 Dec 2024 15:42:26 -0500 Subject: [PATCH 08/12] Add Source checks to Instrumentor --- .../deleteinstrumentedapplication/common.go | 17 ++++++++++++- .../instrumentedapplication_controller.go | 24 +++++++++++++++---- .../workload_controllers.go | 17 ++++++++++++- 3 files changed, 52 insertions(+), 6 deletions(-) diff --git a/instrumentor/controllers/deleteinstrumentedapplication/common.go b/instrumentor/controllers/deleteinstrumentedapplication/common.go index d70b9c2f8..9bfe973c6 100644 --- a/instrumentor/controllers/deleteinstrumentedapplication/common.go +++ b/instrumentor/controllers/deleteinstrumentedapplication/common.go @@ -7,6 +7,7 @@ import ( "github.com/odigos-io/odigos/common/consts" "github.com/odigos-io/odigos/k8sutils/pkg/workload" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/log" @@ -21,7 +22,21 @@ func reconcileWorkloadObject(ctx context.Context, kubeClient client.Client, work } if instEffectiveEnabled { - return nil + // Check if a Source object exists for this workload + // TODO: Move this to IsWorkloadInstrumentationEffectiveEnabled (creates import loop right now) + sourceList := &odigosv1.SourceList{} + selector := labels.SelectorFromSet(labels.Set{ + "odigos.io/workload-name": workloadObject.GetName(), + "odigos.io/workload-namespace": workloadObject.GetNamespace(), + "odigos.io/workload-kind": workloadObject.GetObjectKind().GroupVersionKind().Kind, + }) + err := kubeClient.List(ctx, sourceList, &client.ListOptions{LabelSelector: selector}) + if err != nil { + return err + } + if len(sourceList.Items) == 0 { + return nil + } } if err := deleteWorkloadInstrumentedApplication(ctx, kubeClient, workloadObject); err != nil { diff --git a/instrumentor/controllers/deleteinstrumentedapplication/instrumentedapplication_controller.go b/instrumentor/controllers/deleteinstrumentedapplication/instrumentedapplication_controller.go index a3c504cca..71d1b65c1 100644 --- a/instrumentor/controllers/deleteinstrumentedapplication/instrumentedapplication_controller.go +++ b/instrumentor/controllers/deleteinstrumentedapplication/instrumentedapplication_controller.go @@ -20,11 +20,12 @@ import ( "context" "fmt" + odigosv1 "github.com/odigos-io/odigos/api/odigos/v1alpha1" "github.com/odigos-io/odigos/k8sutils/pkg/workload" - odigosv1 "github.com/odigos-io/odigos/api/odigos/v1alpha1" appsv1 "k8s.io/api/apps/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" @@ -90,9 +91,24 @@ func (r *InstrumentedApplicationReconciler) Reconcile(ctx context.Context, req c } if !instEffectiveEnabled { - logger.Info("Deleting instrumented application for non-enabled workload") - err := r.Client.Delete(ctx, &instrumentedApplication) - return ctrl.Result{}, client.IgnoreNotFound(err) + // Check if a Source object exists for this workload + // TODO: Move this to IsWorkloadInstrumentationEffectiveEnabled (creates import loop right now) + sourceList := &odigosv1.SourceList{} + selector := labels.SelectorFromSet(labels.Set{ + "odigos.io/workload-name": workloadObject.GetName(), + "odigos.io/workload-namespace": workloadObject.GetNamespace(), + "odigos.io/workload-kind": workloadObject.GetObjectKind().GroupVersionKind().Kind, + }) + err := r.Client.List(ctx, sourceList, &client.ListOptions{LabelSelector: selector}) + if err != nil { + return ctrl.Result{}, err + } + if len(sourceList.Items) == 0 { + logger.Info("Deleting instrumented application for non-enabled workload") + err := r.Client.Delete(ctx, &instrumentedApplication) + return ctrl.Result{}, client.IgnoreNotFound(err) + } + } return ctrl.Result{}, nil diff --git a/instrumentor/controllers/startlangdetection/workload_controllers.go b/instrumentor/controllers/startlangdetection/workload_controllers.go index b8085d4dc..a197780b0 100644 --- a/instrumentor/controllers/startlangdetection/workload_controllers.go +++ b/instrumentor/controllers/startlangdetection/workload_controllers.go @@ -4,6 +4,7 @@ import ( "context" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" "sigs.k8s.io/yaml" "k8s.io/apimachinery/pkg/runtime" @@ -59,7 +60,21 @@ func reconcileWorkload(ctx context.Context, k8sClient client.Client, objKind wor } if !instrumented { - return ctrl.Result{}, nil + // Check if a Source object exists for this workload + // TODO: Move this to IsWorkloadInstrumentationEffectiveEnabled (creates import loop right now) + sourceList := &odigosv1.SourceList{} + selector := labels.SelectorFromSet(labels.Set{ + "odigos.io/workload-name": obj.GetName(), + "odigos.io/workload-namespace": obj.GetNamespace(), + "odigos.io/workload-kind": obj.GetObjectKind().GroupVersionKind().Kind, + }) + err := k8sClient.List(ctx, sourceList, &client.ListOptions{LabelSelector: selector}) + if err != nil { + return ctrl.Result{}, err + } + if len(sourceList.Items) == 0 { + return ctrl.Result{}, nil + } } err = requestOdigletsToCalculateRuntimeDetails(ctx, k8sClient, instConfigName, req.Namespace, obj, scheme) From adfc696bf29361ab81608f5e854087edbd8bf98b Mon Sep 17 00:00:00 2001 From: Mike Dame Date: Mon, 23 Dec 2024 11:14:30 -0500 Subject: [PATCH 09/12] Add GetSourceListForWorkload function --- api/odigos/v1alpha1/source_types.go | 21 +++++++++++++++++++ .../deleteinstrumentedapplication/common.go | 11 ++-------- .../instrumentedapplication_controller.go | 12 ++--------- .../workload_controllers.go | 11 ++-------- 4 files changed, 27 insertions(+), 28 deletions(-) diff --git a/api/odigos/v1alpha1/source_types.go b/api/odigos/v1alpha1/source_types.go index 3dd31ef63..f3969810d 100644 --- a/api/odigos/v1alpha1/source_types.go +++ b/api/odigos/v1alpha1/source_types.go @@ -17,7 +17,11 @@ limitations under the License. package v1alpha1 import ( + "context" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" + "sigs.k8s.io/controller-runtime/pkg/client" "github.com/odigos-io/odigos/k8sutils/pkg/workload" ) @@ -62,6 +66,23 @@ type SourceList struct { Items []Source `json:"items"` } +// GetSourceListForWorkload returns a SourceList of all Sources that have matching +// workload name, namespace, and kind labels for an object. In theory, this should only +// ever return a list with 0 or 1 items, but due diligence should handle unexpected cases. +func GetSourceListForWorkload(ctx context.Context, kubeClient client.Client, obj client.Object) (*SourceList, error) { + sourceList := &SourceList{} + selector := labels.SelectorFromSet(labels.Set{ + "odigos.io/workload-name": obj.GetName(), + "odigos.io/workload-namespace": obj.GetNamespace(), + "odigos.io/workload-kind": obj.GetObjectKind().GroupVersionKind().Kind, + }) + err := kubeClient.List(ctx, sourceList, &client.ListOptions{LabelSelector: selector}) + if err != nil { + return nil, err + } + return sourceList, nil +} + func init() { SchemeBuilder.Register(&Source{}, &SourceList{}) } diff --git a/instrumentor/controllers/deleteinstrumentedapplication/common.go b/instrumentor/controllers/deleteinstrumentedapplication/common.go index 9bfe973c6..ef5ee898f 100644 --- a/instrumentor/controllers/deleteinstrumentedapplication/common.go +++ b/instrumentor/controllers/deleteinstrumentedapplication/common.go @@ -3,11 +3,11 @@ package deleteinstrumentedapplication import ( "context" + "github.com/odigos-io/odigos/api/odigos/v1alpha1" odigosv1 "github.com/odigos-io/odigos/api/odigos/v1alpha1" "github.com/odigos-io/odigos/common/consts" "github.com/odigos-io/odigos/k8sutils/pkg/workload" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/log" @@ -23,14 +23,7 @@ func reconcileWorkloadObject(ctx context.Context, kubeClient client.Client, work if instEffectiveEnabled { // Check if a Source object exists for this workload - // TODO: Move this to IsWorkloadInstrumentationEffectiveEnabled (creates import loop right now) - sourceList := &odigosv1.SourceList{} - selector := labels.SelectorFromSet(labels.Set{ - "odigos.io/workload-name": workloadObject.GetName(), - "odigos.io/workload-namespace": workloadObject.GetNamespace(), - "odigos.io/workload-kind": workloadObject.GetObjectKind().GroupVersionKind().Kind, - }) - err := kubeClient.List(ctx, sourceList, &client.ListOptions{LabelSelector: selector}) + sourceList, err := v1alpha1.GetSourceListForWorkload(ctx, kubeClient, workloadObject) if err != nil { return err } diff --git a/instrumentor/controllers/deleteinstrumentedapplication/instrumentedapplication_controller.go b/instrumentor/controllers/deleteinstrumentedapplication/instrumentedapplication_controller.go index 71d1b65c1..52866a90b 100644 --- a/instrumentor/controllers/deleteinstrumentedapplication/instrumentedapplication_controller.go +++ b/instrumentor/controllers/deleteinstrumentedapplication/instrumentedapplication_controller.go @@ -20,12 +20,12 @@ import ( "context" "fmt" + "github.com/odigos-io/odigos/api/odigos/v1alpha1" odigosv1 "github.com/odigos-io/odigos/api/odigos/v1alpha1" "github.com/odigos-io/odigos/k8sutils/pkg/workload" appsv1 "k8s.io/api/apps/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" @@ -92,14 +92,7 @@ func (r *InstrumentedApplicationReconciler) Reconcile(ctx context.Context, req c if !instEffectiveEnabled { // Check if a Source object exists for this workload - // TODO: Move this to IsWorkloadInstrumentationEffectiveEnabled (creates import loop right now) - sourceList := &odigosv1.SourceList{} - selector := labels.SelectorFromSet(labels.Set{ - "odigos.io/workload-name": workloadObject.GetName(), - "odigos.io/workload-namespace": workloadObject.GetNamespace(), - "odigos.io/workload-kind": workloadObject.GetObjectKind().GroupVersionKind().Kind, - }) - err := r.Client.List(ctx, sourceList, &client.ListOptions{LabelSelector: selector}) + sourceList, err := v1alpha1.GetSourceListForWorkload(ctx, r.Client, workloadObject) if err != nil { return ctrl.Result{}, err } @@ -108,7 +101,6 @@ func (r *InstrumentedApplicationReconciler) Reconcile(ctx context.Context, req c err := r.Client.Delete(ctx, &instrumentedApplication) return ctrl.Result{}, client.IgnoreNotFound(err) } - } return ctrl.Result{}, nil diff --git a/instrumentor/controllers/startlangdetection/workload_controllers.go b/instrumentor/controllers/startlangdetection/workload_controllers.go index a197780b0..0ef0e7489 100644 --- a/instrumentor/controllers/startlangdetection/workload_controllers.go +++ b/instrumentor/controllers/startlangdetection/workload_controllers.go @@ -4,13 +4,13 @@ import ( "context" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/labels" "sigs.k8s.io/yaml" "k8s.io/apimachinery/pkg/runtime" "sigs.k8s.io/controller-runtime/pkg/log" + "github.com/odigos-io/odigos/api/odigos/v1alpha1" odigosv1 "github.com/odigos-io/odigos/api/odigos/v1alpha1" "github.com/odigos-io/odigos/k8sutils/pkg/workload" "k8s.io/apimachinery/pkg/types" @@ -61,14 +61,7 @@ func reconcileWorkload(ctx context.Context, k8sClient client.Client, objKind wor if !instrumented { // Check if a Source object exists for this workload - // TODO: Move this to IsWorkloadInstrumentationEffectiveEnabled (creates import loop right now) - sourceList := &odigosv1.SourceList{} - selector := labels.SelectorFromSet(labels.Set{ - "odigos.io/workload-name": obj.GetName(), - "odigos.io/workload-namespace": obj.GetNamespace(), - "odigos.io/workload-kind": obj.GetObjectKind().GroupVersionKind().Kind, - }) - err := k8sClient.List(ctx, sourceList, &client.ListOptions{LabelSelector: selector}) + sourceList, err := v1alpha1.GetSourceListForWorkload(ctx, k8sClient, obj) if err != nil { return ctrl.Result{}, err } From 32c3afe677a34a61e1d90262ad56cb369c85761f Mon Sep 17 00:00:00 2001 From: Mike Dame Date: Mon, 23 Dec 2024 13:09:24 -0500 Subject: [PATCH 10/12] Add SourceReconciler to deleteinstrumentedapplication controller --- .../deleteinstrumentedapplication/manager.go | 13 +++ .../source_controller.go | 95 +++++++++++++++++++ .../startlangdetection/source_controller.go | 4 + 3 files changed, 112 insertions(+) create mode 100644 instrumentor/controllers/deleteinstrumentedapplication/source_controller.go diff --git a/instrumentor/controllers/deleteinstrumentedapplication/manager.go b/instrumentor/controllers/deleteinstrumentedapplication/manager.go index eb99d5347..e107fd35a 100644 --- a/instrumentor/controllers/deleteinstrumentedapplication/manager.go +++ b/instrumentor/controllers/deleteinstrumentedapplication/manager.go @@ -74,6 +74,19 @@ func SetupWithManager(mgr ctrl.Manager) error { return err } + err = builder. + ControllerManagedBy(mgr). + Named("deleteinstrumentedapplication-source"). + WithEventFilter(&SourceDeletedPredicate{}). + For(&odigosv1.Source{}). + Complete(&SourceReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + }) +if err != nil { + return err +} + return nil } diff --git a/instrumentor/controllers/deleteinstrumentedapplication/source_controller.go b/instrumentor/controllers/deleteinstrumentedapplication/source_controller.go new file mode 100644 index 000000000..0f611c6ef --- /dev/null +++ b/instrumentor/controllers/deleteinstrumentedapplication/source_controller.go @@ -0,0 +1,95 @@ +/* +Copyright 2022. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package deleteinstrumentedapplication + +import ( + "context" + + "github.com/odigos-io/odigos/api/odigos/v1alpha1" + "github.com/odigos-io/odigos/k8sutils/pkg/workload" + + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "sigs.k8s.io/controller-runtime/pkg/event" + "sigs.k8s.io/controller-runtime/pkg/log" +) + +// Added by startlangdetection controller when Source is created +var instrumentedApplicationFinalizer = "odigos.io/source-instrumentedapplication-finalizer" + +type SourceDeletedPredicate struct{} + +func (i *SourceDeletedPredicate) Create(_ event.CreateEvent) bool { + return false +} + +func (i *SourceDeletedPredicate) Update(_ event.UpdateEvent) bool { + // We are actually looking for Update events that add a DeletionTimestamp + // This is so we can still get the workload from the Source object and remove the finalizer + // Then actual deletion of the Source will proceed + return true +} + +func (i *SourceDeletedPredicate) Delete(_ event.DeleteEvent) bool { + return true +} + +func (i *SourceDeletedPredicate) Generic(_ event.GenericEvent) bool { + return false +} + +type SourceReconciler struct { + client.Client + Scheme *runtime.Scheme +} + +func (r *SourceReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + logger := log.FromContext(ctx) + logger.Info("Reconciling Deleted Source object", "name", req.Name, "namespace", req.Namespace) + + source := &v1alpha1.Source{} + err := r.Get(ctx, req.NamespacedName, source) + if err != nil { + return ctrl.Result{}, client.IgnoreNotFound(err) + } + + if !source.DeletionTimestamp.IsZero() { + logger.Info("Reconciling workload for deleted Source object", "name", req.Name, "namespace", req.Namespace) + obj := workload.ClientObjectFromWorkloadKind(source.Spec.Workload.Kind) + err = r.Client.Get(ctx, types.NamespacedName{Name: source.Spec.Workload.Name, Namespace: source.Spec.Workload.Namespace}, obj) + if err != nil { + // TODO: Deleted objects should be filtered in the event filter + return ctrl.Result{}, err + } + + if controllerutil.ContainsFinalizer(source, instrumentedApplicationFinalizer) { + controllerutil.RemoveFinalizer(source, instrumentedApplicationFinalizer) + if err := r.Update(ctx, source); err != nil { + return ctrl.Result{}, err + } + } + + err = reconcileWorkloadObject(ctx, r.Client, obj) + if err != nil { + return ctrl.Result{}, err + } + } + return ctrl.Result{}, nil +} diff --git a/instrumentor/controllers/startlangdetection/source_controller.go b/instrumentor/controllers/startlangdetection/source_controller.go index 6c8c510dd..6894e7a55 100644 --- a/instrumentor/controllers/startlangdetection/source_controller.go +++ b/instrumentor/controllers/startlangdetection/source_controller.go @@ -16,6 +16,8 @@ import ( var ( sourceFinalizer = "odigos.io/source-finalizer" + // TODO: Needed until InstrumentedApplication is removed + instrumentedApplicationFinalizer = "odigos.io/source-instrumentedapplication-finalizer" workloadNameLabel = "odigos.io/workload-name" workloadNamespaceLabel = "odigos.io/workload-namespace" @@ -47,6 +49,8 @@ func (r *SourceReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctr if source.DeletionTimestamp.IsZero() { if !controllerutil.ContainsFinalizer(source, sourceFinalizer) { controllerutil.AddFinalizer(source, sourceFinalizer) + // Removed by deleteinstrumentedapplication controller + controllerutil.AddFinalizer(source, instrumentedApplicationFinalizer) if source.Labels == nil { source.Labels = make(map[string]string) From b44f4421615d247e2a5a2e2c7d09ab891efee8e3 Mon Sep 17 00:00:00 2001 From: Mike Dame Date: Mon, 23 Dec 2024 13:43:11 -0500 Subject: [PATCH 11/12] Enable build and e2e workflows for feature branch --- .github/workflows/build.yaml | 3 ++- .github/workflows/e2e.yaml | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index fc8e2f786..7a2055333 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -6,6 +6,7 @@ on: branches: - main - stable + - feature/source-crd jobs: build-autoscaler: @@ -158,4 +159,4 @@ jobs: - name: Test procdiscovery module working-directory: ./procdiscovery run: | - go test -v ./... \ No newline at end of file + go test -v ./... diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml index b1ca6702c..d531d8edf 100644 --- a/.github/workflows/e2e.yaml +++ b/.github/workflows/e2e.yaml @@ -6,6 +6,7 @@ on: branches: - main - stable + - feature/source-crd concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} From ef8f196feb99f05d1804e4971f66d4f4b44ecda7 Mon Sep 17 00:00:00 2001 From: Mike Dame Date: Mon, 23 Dec 2024 15:58:17 -0500 Subject: [PATCH 12/12] Add Instrumentor Sources RBAC to Helm chart --- .../templates/instrumentor/clusterrole.yaml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/helm/odigos/templates/instrumentor/clusterrole.yaml b/helm/odigos/templates/instrumentor/clusterrole.yaml index d1d479f72..a61c654fb 100644 --- a/helm/odigos/templates/instrumentor/clusterrole.yaml +++ b/helm/odigos/templates/instrumentor/clusterrole.yaml @@ -78,3 +78,21 @@ rules: - patch - update - watch + - apiGroups: + - odigos.io + resources: + - sources + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - odigos.io + resources: + - sources/finalizers + verbs: + - update