From 913dd80a544bb870e06d27f68f28db2d81f0938e Mon Sep 17 00:00:00 2001
From: David <david@odigos.io>
Date: Fri, 15 Nov 2024 14:09:53 +0000
Subject: [PATCH 01/10] Support Kubernetes version 1.20.25

---
 autoscaler/main.go                           | 68 ++++++++++++++++++--
 autoscaler/migration.go                      | 39 +++++++++++
 cli/cmd/install.go                           |  2 +-
 cli/cmd/resources/odiglet.go                 | 11 +++-
 helm/odigos/Chart.yaml                       |  2 +-
 helm/odigos/templates/odiglet/daemonset.yaml |  2 +
 6 files changed, 113 insertions(+), 11 deletions(-)

diff --git a/autoscaler/main.go b/autoscaler/main.go
index 2d55a5dae..68a1aafb6 100644
--- a/autoscaler/main.go
+++ b/autoscaler/main.go
@@ -19,7 +19,9 @@ package main
 import (
 	"context"
 	"flag"
+	"fmt"
 	"os"
+	"strconv"
 	"strings"
 
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
@@ -45,7 +47,9 @@ import (
 	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/apimachinery/pkg/types"
 	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
+	"k8s.io/client-go/discovery"
 	clientgoscheme "k8s.io/client-go/kubernetes/scheme"
+	"k8s.io/client-go/rest"
 	ctrl "sigs.k8s.io/controller-runtime"
 	"sigs.k8s.io/controller-runtime/pkg/healthz"
 	ctrlzap "sigs.k8s.io/controller-runtime/pkg/log/zap"
@@ -126,7 +130,14 @@ func main() {
 	nsSelector := client.InNamespace(odigosNs).AsSelector()
 	clusterCollectorLabelSelector := labels.Set(gateway.ClusterCollectorGateway).AsSelector()
 
-	mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
+	cfg := ctrl.GetConfigOrDie()
+	// Determine if we need to use a non-caching client based on the Kubernetes version, version <1.23 has issues when using caching client
+	useNonCachingClient, err := shouldUseNonCachingClient(cfg)
+	if err != nil {
+		setupLog.Error(err, "unable to determine Kubernetes version")
+		os.Exit(1)
+	}
+	mgr, err := ctrl.NewManager(cfg, ctrl.Options{
 		Scheme: scheme,
 		Metrics: metricsserver.Options{
 			BindAddress: metricsAddr,
@@ -161,11 +172,28 @@ func main() {
 		setupLog.Error(err, "unable to start manager")
 		os.Exit(1)
 	}
-
-	err = MigrateCollectorsWorkloadToNewLabels(context.Background(), mgr.GetClient(), odigosNs)
-	if err != nil {
-		setupLog.Error(err, "unable to migrate collectors workload to new labels")
-		os.Exit(1)
+	// Ver < 1.23
+	var migrationClient client.Client
+	if useNonCachingClient {
+		// Create a non-caching client for versions < 1.23
+		migrationClient, err = client.New(cfg, client.Options{Scheme: scheme})
+		if err != nil {
+			setupLog.Error(err, "unable to create non-caching client for migration")
+			os.Exit(1)
+		}
+		// Migrate collectors workload to new labels using old API
+		err = OldVerKubernetesMigrateCollectorsWorkloadToNewLabels(context.Background(), migrationClient, odigosNs)
+		if err != nil {
+			setupLog.Error(err, "legacy unable to migrate collectors workload to new labels")
+			os.Exit(1)
+		}
+	} else {
+		// Use the cached client for versions >= 1.23
+		err = MigrateCollectorsWorkloadToNewLabels(context.Background(), mgr.GetClient(), odigosNs)
+		if err != nil {
+			setupLog.Error(err, "unable to migrate collectors workload to new labels")
+			os.Exit(1)
+		}
 	}
 
 	// The name processor is used to transform device ids injected with the virtual device,
@@ -294,3 +322,31 @@ func isMetricsServerInstalled(mgr ctrl.Manager, logger logr.Logger) bool {
 	logger.V(0).Info("Metrics server found")
 	return true
 }
+
+// Kubernetes version <1.23 has issues when using caching client and also DeleteAllOf is not supported in versions <1.23
+// so we need to use legacy delete for versions <1.23
+func shouldUseNonCachingClient(cfg *rest.Config) (bool, error) {
+	discoveryClient, err := discovery.NewDiscoveryClientForConfig(cfg)
+	if err != nil {
+		return false, err
+	}
+
+	serverVersion, err := discoveryClient.ServerVersion()
+	if err != nil {
+		return false, err
+	}
+
+	// Parse the major and minor versions
+	major, err := strconv.Atoi(serverVersion.Major)
+	if err != nil {
+		return false, fmt.Errorf("failed to parse major version: %w", err)
+	}
+
+	minor, err := strconv.Atoi(strings.TrimSuffix(serverVersion.Minor, "+"))
+	if err != nil {
+		return false, fmt.Errorf("failed to parse minor version: %w", err)
+	}
+
+	// Use non-caching client if the version is less than 1.23
+	return major < 1 || (major == 1 && minor < 23), nil
+}
diff --git a/autoscaler/migration.go b/autoscaler/migration.go
index b53b3d32c..7a3f6a8f3 100644
--- a/autoscaler/migration.go
+++ b/autoscaler/migration.go
@@ -50,3 +50,42 @@ func MigrateCollectorsWorkloadToNewLabels(ctx context.Context, c client.Client,
 	return nil
 
 }
+func OldVerKubernetesMigrateCollectorsWorkloadToNewLabels(ctx context.Context, c client.Client, ns string) error {
+	// Use the legacy method for Kubernetes versions < 1.23
+
+	// List and delete Deployments with the label "odigos.io/collector": "true"
+	preV1_0_91LabelSelectorGateway := client.MatchingLabels{"odigos.io/collector": "true"}
+	var deployments appsv1.DeploymentList
+	if err := c.List(ctx, &deployments, client.InNamespace(ns), preV1_0_91LabelSelectorGateway); err != nil {
+		return err
+	}
+	for _, deployment := range deployments.Items {
+		if err := c.Delete(ctx, &deployment); err != nil {
+			return err
+		}
+	}
+
+	// List and delete Services with the label "odigos.io/collector": "true"
+	var services corev1.ServiceList
+	if err := c.List(ctx, &services, client.InNamespace(ns), preV1_0_91LabelSelectorGateway); err != nil {
+		return err
+	}
+	for _, service := range services.Items {
+		if err := c.Delete(ctx, &service); err != nil {
+			return err
+		}
+	}
+
+	// List and delete DaemonSets with the label "odigos.io/data-collection": "true"
+	preV1_0_91LabelSelectorNodeCollector := client.MatchingLabels{"odigos.io/data-collection": "true"}
+	var daemonSets appsv1.DaemonSetList
+	if err := c.List(ctx, &daemonSets, client.InNamespace(ns), preV1_0_91LabelSelectorNodeCollector); err != nil {
+		return err
+	}
+	for _, daemonSet := range daemonSets.Items {
+		if err := c.Delete(ctx, &daemonSet); err != nil {
+			return err
+		}
+	}
+	return nil
+}
diff --git a/cli/cmd/install.go b/cli/cmd/install.go
index b7f5f9892..1c68789bc 100644
--- a/cli/cmd/install.go
+++ b/cli/cmd/install.go
@@ -50,7 +50,7 @@ var (
 var (
 	// minK8SVersionForInstallation is the minimum Kubernetes version required for Odigos installation
 	// this value must be in sync with the one defined in the kubeVersion field in Chart.yaml
-	minK8SVersionForInstallation = version.MustParse("v1.23.0")
+	minK8SVersionForInstallation = version.MustParse("v1.20.15")
 )
 
 type ResourceCreationFunc func(ctx context.Context, cmd *cobra.Command, client *kube.Client, ns string) error
diff --git a/cli/cmd/resources/odiglet.go b/cli/cmd/resources/odiglet.go
index b5cad80b6..d1a9304f5 100644
--- a/cli/cmd/resources/odiglet.go
+++ b/cli/cmd/resources/odiglet.go
@@ -19,6 +19,7 @@ import (
 	rbacv1 "k8s.io/api/rbac/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/util/intstr"
+	k8sversion "k8s.io/apimachinery/pkg/util/version"
 )
 
 const (
@@ -446,8 +447,12 @@ func NewOdigletDaemonSet(ns string, version string, imagePrefix string, imageNam
 	maxUnavailable := intstr.FromString("50%")
 	// maxSurge is the number of pods that can be created above the desired number of pods.
 	// we do not want more then 1 odiglet pod on the same node as it is not supported by the eBPF.
-	maxSurge := intstr.FromInt(0)
-
+	// Only set maxSurge if Kubernetes version is >= 1.22
+	var maxSurge *intstr.IntOrString
+	if autodetect.CurrentKubernetesVersion.Version.AtLeast(k8sversion.MustParse("v1.22")) {
+		maxSurgeValue := intstr.FromInt(0)
+		maxSurge = &maxSurgeValue
+	}
 	return &appsv1.DaemonSet{
 		TypeMeta: metav1.TypeMeta{
 			Kind:       "DaemonSet",
@@ -470,7 +475,7 @@ func NewOdigletDaemonSet(ns string, version string, imagePrefix string, imageNam
 				Type: appsv1.RollingUpdateDaemonSetStrategyType,
 				RollingUpdate: &appsv1.RollingUpdateDaemonSet{
 					MaxUnavailable: &maxUnavailable,
-					MaxSurge:       &maxSurge,
+					MaxSurge:       maxSurge, // Set conditionally
 				},
 			},
 			Template: corev1.PodTemplateSpec{
diff --git a/helm/odigos/Chart.yaml b/helm/odigos/Chart.yaml
index f7cb06b95..c6145aa53 100644
--- a/helm/odigos/Chart.yaml
+++ b/helm/odigos/Chart.yaml
@@ -8,4 +8,4 @@ version: "0.0.0"
 appVersion: "v0.0.0"
 icon: https://d2q89wckrml3k4.cloudfront.net/logo.png
 # minimum kubernetes version required, this value must be in sync with the CLI install value
-kubeVersion: ">= 1.23.0"
+kubeVersion: ">= 1.20.15"
diff --git a/helm/odigos/templates/odiglet/daemonset.yaml b/helm/odigos/templates/odiglet/daemonset.yaml
index cfd0fd5dd..26d506fd6 100644
--- a/helm/odigos/templates/odiglet/daemonset.yaml
+++ b/helm/odigos/templates/odiglet/daemonset.yaml
@@ -11,7 +11,9 @@ spec:
       app.kubernetes.io/name: odiglet
   updateStrategy:
     rollingUpdate:
+      {{- if semverCompare ">=1.22.0" .Capabilities.KubeVersion.Version }}
       maxSurge: 0
+      {{- end }}
       maxUnavailable: 50%
     type: RollingUpdate
   template:

From 7e7a4d2425a88e0cf129c9f0270959481e960337 Mon Sep 17 00:00:00 2001
From: David <david@odigos.io>
Date: Fri, 15 Nov 2024 14:09:53 +0000
Subject: [PATCH 02/10] Fix bug in k8s version and update e2e test

---
 .github/workflows/e2e.yaml   |  6 +++---
 cli/cmd/install.go           | 20 +++++++++-----------
 cli/cmd/resources/odiglet.go |  2 +-
 cli/pkg/autodetect/kind.go   |  4 ++--
 4 files changed, 15 insertions(+), 17 deletions(-)

diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml
index eec69175e..6cbd99e52 100644
--- a/.github/workflows/e2e.yaml
+++ b/.github/workflows/e2e.yaml
@@ -65,7 +65,7 @@ jobs:
       fail-fast: false
       matrix:
         kube-version:
-          - "1.23"
+          - "1.20.15"
           - "1.30"
         test-scenario:
           - "multi-apps"
@@ -74,8 +74,8 @@ jobs:
           - "cli-upgrade"
           - "workload-lifecycle"
         include:
-          - kube-version: "1.23"
-            kind-image: "kindest/node:v1.23.17@sha256:14d0a9a892b943866d7e6be119a06871291c517d279aedb816a4b4bc0ec0a5b3"
+          - kube-version: "1.20.15"
+            kind-image: "kindest/node:v1.20.15@sha256:a32bf55309294120616886b5338f95dd98a2f7231519c7dedcec32ba29699394"
           - kube-version: "1.30"
             kind-image: "kindest/node:v1.30.0@sha256:047357ac0cfea04663786a612ba1eaba9702bef25227a794b52890dd8bcd692e"
     steps:
diff --git a/cli/cmd/install.go b/cli/cmd/install.go
index 1c68789bc..05f36c705 100644
--- a/cli/cmd/install.go
+++ b/cli/cmd/install.go
@@ -80,23 +80,21 @@ This command will install k8s components that will auto-instrument your applicat
 		// Check if the cluster meets the minimum requirements
 		kc := cmd.Flag("kubeconfig").Value.String()
 		details, err := autodetect.DetectK8SClusterDetails(ctx, kc, client)
-		if err == nil {
-			autodetect.CurrentKubernetesVersion = autodetect.KubernetesVersion{
-				Kind:    details.Kind,
-				Version: details.K8SVersion,
-			}
+		if !errors.Is(err, autodetect.ErrCannotDetectClusterKind) {
+			autodetect.CurrentKubernetesVersion.Kind = details.Kind
+		} else {
+			fmt.Println("Unknown Kubernetes cluster detected, proceeding with installation")
+		}
+
+		if !errors.Is(err, autodetect.ErrCannotDetectK8sVersion) {
+			autodetect.CurrentKubernetesVersion.Version = details.K8SVersion
 			if details.K8SVersion.LessThan(minK8SVersionForInstallation) {
 				fmt.Printf("\033[31mERROR\033[0m Odigos requires Kubernetes version %s or higher but found %s, aborting\n", minK8SVersionForInstallation.String(), details.K8SVersion.String())
 				os.Exit(1)
 			}
 			fmt.Printf("Detected cluster: %s Kubernetes version: %s\n", details.Kind, details.K8SVersion.String())
 		} else {
-			if errors.Is(err, autodetect.ErrCannotDetectClusterKind) {
-				fmt.Println("Unknown Kubernetes cluster detected, proceeding with installation")
-			}
-			if errors.Is(err, autodetect.ErrCannotDetectK8sVersion) {
-				fmt.Println("Unknown Kubernetes version detected, proceeding with installation")
-			}
+			fmt.Println("Unknown Kubernetes version detected, proceeding with installation")
 		}
 
 		var odigosProToken string
diff --git a/cli/cmd/resources/odiglet.go b/cli/cmd/resources/odiglet.go
index d1a9304f5..7818723d2 100644
--- a/cli/cmd/resources/odiglet.go
+++ b/cli/cmd/resources/odiglet.go
@@ -449,7 +449,7 @@ func NewOdigletDaemonSet(ns string, version string, imagePrefix string, imageNam
 	// we do not want more then 1 odiglet pod on the same node as it is not supported by the eBPF.
 	// Only set maxSurge if Kubernetes version is >= 1.22
 	var maxSurge *intstr.IntOrString
-	if autodetect.CurrentKubernetesVersion.Version.AtLeast(k8sversion.MustParse("v1.22")) {
+	if autodetect.CurrentKubernetesVersion.Version != nil && autodetect.CurrentKubernetesVersion.Version.AtLeast(k8sversion.MustParse("v1.22")) {
 		maxSurgeValue := intstr.FromInt(0)
 		maxSurge = &maxSurgeValue
 	}
diff --git a/cli/pkg/autodetect/kind.go b/cli/pkg/autodetect/kind.go
index fb543f8bb..73cbaadb6 100644
--- a/cli/pkg/autodetect/kind.go
+++ b/cli/pkg/autodetect/kind.go
@@ -5,9 +5,9 @@ import (
 	"errors"
 	"fmt"
 
-	"k8s.io/apimachinery/pkg/util/version"
 	"github.com/odigos-io/odigos/cli/pkg/kube"
 	k8sutils "github.com/odigos-io/odigos/k8sutils/pkg/client"
+	"k8s.io/apimachinery/pkg/util/version"
 )
 
 type Kind string
@@ -77,5 +77,5 @@ func DetectK8SClusterDetails(ctx context.Context, kc string, client *kube.Client
 		}, nil
 	}
 
-	return ClusterDetails{}, ErrCannotDetectClusterKind
+	return ClusterDetails{K8SVersion: ver}, ErrCannotDetectClusterKind
 }

From e7447bb31823bfea2984493bc8ab8d99c540a87c Mon Sep 17 00:00:00 2001
From: David <david@odigos.io>
Date: Fri, 15 Nov 2024 14:09:53 +0000
Subject: [PATCH 03/10] Fix cli upgrade

---
 .../controllers/datacollection/daemonset.go   | 50 ++++++++++++++---
 cli/cmd/resources/odiglet.go                  | 17 +++---
 cli/go.mod                                    | 12 +++-
 cli/go.sum                                    | 22 ++++++++
 cli/pkg/kube/client.go                        | 55 ++++++++++++++++++-
 5 files changed, 137 insertions(+), 19 deletions(-)

diff --git a/autoscaler/controllers/datacollection/daemonset.go b/autoscaler/controllers/datacollection/daemonset.go
index 0ea7df5a9..fb3affb59 100644
--- a/autoscaler/controllers/datacollection/daemonset.go
+++ b/autoscaler/controllers/datacollection/daemonset.go
@@ -3,6 +3,8 @@ package datacollection
 import (
 	"context"
 	"fmt"
+	"strconv"
+	"strings"
 	"sync"
 	"time"
 
@@ -10,6 +12,7 @@ import (
 	"github.com/odigos-io/odigos/autoscaler/controllers/common"
 	"github.com/odigos-io/odigos/autoscaler/controllers/datacollection/custom"
 	"github.com/odigos-io/odigos/autoscaler/utils"
+
 	"github.com/odigos-io/odigos/k8sutils/pkg/consts"
 	appsv1 "k8s.io/api/apps/v1"
 	corev1 "k8s.io/api/core/v1"
@@ -18,6 +21,8 @@ import (
 	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/apimachinery/pkg/types"
 	"k8s.io/apimachinery/pkg/util/intstr"
+	"k8s.io/client-go/discovery"
+	"k8s.io/client-go/rest"
 	ctrl "sigs.k8s.io/controller-runtime"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 	"sigs.k8s.io/controller-runtime/pkg/log"
@@ -179,7 +184,15 @@ func getDesiredDaemonSet(datacollection *odigosv1.CollectorsGroup, configData st
 	maxUnavailable := intstr.FromString("50%")
 	// maxSurge is the number of pods that can be created above the desired number of pods.
 	// we do not want more then 1 datacollection pod on the same node as they need to bind to oltp ports.
-	maxSurge := intstr.FromInt(0)
+	rollingUpdate := &appsv1.RollingUpdateDaemonSet{
+		MaxUnavailable: &maxUnavailable,
+	}
+	cfg := ctrl.GetConfigOrDie()
+	versionSupported, err := isVersionSupported(cfg, 1, 22)
+	if err != nil && versionSupported {
+		maxSurge := intstr.FromInt(0)
+		rollingUpdate.MaxSurge = &maxSurge
+	}
 
 	desiredDs := &appsv1.DaemonSet{
 		ObjectMeta: metav1.ObjectMeta{
@@ -192,11 +205,8 @@ func getDesiredDaemonSet(datacollection *odigosv1.CollectorsGroup, configData st
 				MatchLabels: NodeCollectorsLabels,
 			},
 			UpdateStrategy: appsv1.DaemonSetUpdateStrategy{
-				Type: appsv1.RollingUpdateDaemonSetStrategyType,
-				RollingUpdate: &appsv1.RollingUpdateDaemonSet{
-					MaxUnavailable: &maxUnavailable,
-					MaxSurge:       &maxSurge,
-				},
+				Type:          appsv1.RollingUpdateDaemonSetStrategyType,
+				RollingUpdate: rollingUpdate,
 			},
 			Template: corev1.PodTemplateSpec{
 				ObjectMeta: metav1.ObjectMeta{
@@ -332,7 +342,7 @@ func getDesiredDaemonSet(datacollection *odigosv1.CollectorsGroup, configData st
 		}
 	}
 
-	err := ctrl.SetControllerReference(datacollection, desiredDs, scheme)
+	err = ctrl.SetControllerReference(datacollection, desiredDs, scheme)
 	if err != nil {
 		return nil, err
 	}
@@ -369,3 +379,29 @@ func patchDaemonSet(existing *appsv1.DaemonSet, desired *appsv1.DaemonSet, ctx c
 
 	return updated, nil
 }
+
+func isVersionSupported(cfg *rest.Config, minMajor int, minMinor int) (bool, error) {
+	discoveryClient, err := discovery.NewDiscoveryClientForConfig(cfg)
+	if err != nil {
+		return false, err
+	}
+
+	serverVersion, err := discoveryClient.ServerVersion()
+	if err != nil {
+		return false, err
+	}
+
+	// Parse major and minor versions
+	major, err := strconv.Atoi(serverVersion.Major)
+	if err != nil {
+		return false, fmt.Errorf("failed to parse major version: %w", err)
+	}
+
+	minor, err := strconv.Atoi(strings.TrimSuffix(serverVersion.Minor, "+"))
+	if err != nil {
+		return false, fmt.Errorf("failed to parse minor version: %w", err)
+	}
+
+	// Check if the server version meets or exceeds minMajor.minMinor
+	return major > minMajor || (major == minMajor && minor >= minMinor), nil
+}
diff --git a/cli/cmd/resources/odiglet.go b/cli/cmd/resources/odiglet.go
index 7818723d2..c1588121e 100644
--- a/cli/cmd/resources/odiglet.go
+++ b/cli/cmd/resources/odiglet.go
@@ -448,11 +448,15 @@ func NewOdigletDaemonSet(ns string, version string, imagePrefix string, imageNam
 	// maxSurge is the number of pods that can be created above the desired number of pods.
 	// we do not want more then 1 odiglet pod on the same node as it is not supported by the eBPF.
 	// Only set maxSurge if Kubernetes version is >= 1.22
-	var maxSurge *intstr.IntOrString
+	// Prepare RollingUpdate based on version support for maxSurge
+	rollingUpdate := &appsv1.RollingUpdateDaemonSet{
+		MaxUnavailable: &maxUnavailable,
+	}
 	if autodetect.CurrentKubernetesVersion.Version != nil && autodetect.CurrentKubernetesVersion.Version.AtLeast(k8sversion.MustParse("v1.22")) {
-		maxSurgeValue := intstr.FromInt(0)
-		maxSurge = &maxSurgeValue
+		maxSurge := intstr.FromInt(0)
+		rollingUpdate.MaxSurge = &maxSurge
 	}
+
 	return &appsv1.DaemonSet{
 		TypeMeta: metav1.TypeMeta{
 			Kind:       "DaemonSet",
@@ -472,11 +476,8 @@ func NewOdigletDaemonSet(ns string, version string, imagePrefix string, imageNam
 				},
 			},
 			UpdateStrategy: appsv1.DaemonSetUpdateStrategy{
-				Type: appsv1.RollingUpdateDaemonSetStrategyType,
-				RollingUpdate: &appsv1.RollingUpdateDaemonSet{
-					MaxUnavailable: &maxUnavailable,
-					MaxSurge:       maxSurge, // Set conditionally
-				},
+				Type:          appsv1.RollingUpdateDaemonSetStrategyType,
+				RollingUpdate: rollingUpdate,
 			},
 			Template: corev1.PodTemplateSpec{
 				ObjectMeta: metav1.ObjectMeta{
diff --git a/cli/go.mod b/cli/go.mod
index 0bdf04b91..130f1aa6c 100644
--- a/cli/go.mod
+++ b/cli/go.mod
@@ -15,22 +15,32 @@ require (
 	k8s.io/apiextensions-apiserver v0.31.0
 	k8s.io/apimachinery v0.31.0
 	k8s.io/client-go v0.31.0
+	sigs.k8s.io/controller-runtime v0.19.0
 	sigs.k8s.io/yaml v1.4.0
 )
 
 require (
+	github.com/beorn7/perks v1.0.1 // indirect
+	github.com/cespare/xxhash/v2 v2.3.0 // indirect
 	github.com/fatih/color v1.16.0 // indirect
+	github.com/fsnotify/fsnotify v1.7.0 // indirect
 	github.com/fxamacker/cbor/v2 v2.7.0 // indirect
 	github.com/goccy/go-yaml v1.11.3 // indirect
+	github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
 	github.com/gorilla/websocket v1.5.1 // indirect
 	github.com/mattn/go-colorable v0.1.13 // indirect
 	github.com/mattn/go-isatty v0.0.20 // indirect
 	github.com/moby/spdystream v0.4.0 // indirect
 	github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
+	github.com/prometheus/client_golang v1.19.1 // indirect
+	github.com/prometheus/client_model v0.6.1 // indirect
+	github.com/prometheus/common v0.55.0 // indirect
+	github.com/prometheus/procfs v0.15.1 // indirect
 	github.com/spf13/pflag v1.0.5 // indirect
 	github.com/x448/float16 v0.8.4 // indirect
+	golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect
 	golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
-	sigs.k8s.io/controller-runtime v0.19.0 // indirect
+	gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
 	sigs.k8s.io/gateway-api v1.1.0 // indirect
 )
 
diff --git a/cli/go.sum b/cli/go.sum
index c67c4944a..d36e0ca77 100644
--- a/cli/go.sum
+++ b/cli/go.sum
@@ -1,7 +1,11 @@
 github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
 github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
+github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
+github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
 github.com/cert-manager/cert-manager v1.15.3 h1:/u9T0griwd5MegPfWbB7v0KcVcT9OJrEvPNhc9tl7xQ=
 github.com/cert-manager/cert-manager v1.15.3/go.mod h1:stBge/DTvrhfQMB/93+Y62s+gQgZBsfL1o0C/4AL/mI=
+github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
+github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
 github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -9,10 +13,14 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1
 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/emicklei/go-restful/v3 v3.12.0 h1:y2DdzBAURM29NFF94q6RaY4vjIH1rtwDapwQtU84iWk=
 github.com/emicklei/go-restful/v3 v3.12.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
+github.com/evanphx/json-patch v5.9.0+incompatible h1:fBXyNpNMuTTDdquAq/uisOr2lShz4oaXpDTX2bLe7ls=
+github.com/evanphx/json-patch v5.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
 github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg=
 github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ=
 github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
 github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
+github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
+github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
 github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
 github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
 github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
@@ -37,6 +45,8 @@ github.com/goccy/go-yaml v1.11.3 h1:B3W9IdWbvrUu2OYQGwvU1nZtvMQJPBKgBUuweJjLj6I=
 github.com/goccy/go-yaml v1.11.3/go.mod h1:wKnAMd44+9JAAnGQpWVEgBzGt3YuTaQ4uXoHvE4m7WU=
 github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
 github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
+github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
+github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
 github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
 github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I=
@@ -98,6 +108,14 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
 github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE=
+github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho=
+github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
+github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
+github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc=
+github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8=
+github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
+github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
 github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
 github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
 github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
@@ -119,6 +137,8 @@ go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw=
 go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8=
 go.opentelemetry.io/otel/trace v1.29.0 h1:J/8ZNK4XgR7a21DZUAsbF8pZ5Jcw1VhACmnYt39JTi4=
 go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ=
+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=
 go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
 go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
@@ -170,6 +190,8 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU=
 golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
+gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw=
+gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
 google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
 google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
diff --git a/cli/pkg/kube/client.go b/cli/pkg/kube/client.go
index c36d5fef7..319540e3b 100644
--- a/cli/pkg/kube/client.go
+++ b/cli/pkg/kube/client.go
@@ -5,6 +5,7 @@ import (
 	"fmt"
 	"os"
 	"strconv"
+	"strings"
 
 	k8sutils "github.com/odigos-io/odigos/k8sutils/pkg/client"
 
@@ -21,10 +22,12 @@ import (
 	"github.com/spf13/cobra"
 	apiextensionsclient "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
 	k8slabels "k8s.io/apimachinery/pkg/labels"
+	"k8s.io/client-go/discovery"
 	"k8s.io/client-go/dynamic"
 	"k8s.io/client-go/kubernetes"
 	_ "k8s.io/client-go/plugin/pkg/client/auth"
 	"k8s.io/client-go/rest"
+	ctrl "sigs.k8s.io/controller-runtime"
 )
 
 type Client struct {
@@ -197,7 +200,53 @@ func (c *Client) DeleteOldOdigosSystemObjects(ctx context.Context, resourceAndNa
 	labelSelector := k8slabels.NewSelector().Add(*systemObject).Add(*notLatestVersion).String()
 	resource := resourceAndNamespace.Resource
 	ns := resourceAndNamespace.Namespace
-	return c.Dynamic.Resource(resource).Namespace(ns).DeleteCollection(ctx, metav1.DeleteOptions{}, metav1.ListOptions{
-		LabelSelector: labelSelector,
-	})
+	cfg := ctrl.GetConfigOrDie()
+	versionSupported, err := isVersionSupported(cfg, 1, 23)
+	if err != nil && versionSupported {
+		return c.Dynamic.Resource(resource).Namespace(ns).DeleteCollection(ctx, metav1.DeleteOptions{}, metav1.ListOptions{
+			LabelSelector: labelSelector,
+		})
+	} else {
+		listOptions := metav1.ListOptions{
+			LabelSelector: labelSelector,
+		}
+		resourceList, err := c.Dynamic.Resource(resource).Namespace(ns).List(ctx, listOptions)
+		if err != nil {
+			return fmt.Errorf("failed to list resources: %w", err)
+		}
+
+		// Delete each resource individually
+		for _, item := range resourceList.Items {
+			err = c.Dynamic.Resource(resource).Namespace(ns).Delete(ctx, item.GetName(), metav1.DeleteOptions{})
+			if err != nil {
+				return fmt.Errorf("failed to delete resource %s: %w", item.GetName(), err)
+			}
+		}
+	}
+	return nil
+}
+func isVersionSupported(cfg *rest.Config, minMajor int, minMinor int) (bool, error) {
+	discoveryClient, err := discovery.NewDiscoveryClientForConfig(cfg)
+	if err != nil {
+		return false, err
+	}
+
+	serverVersion, err := discoveryClient.ServerVersion()
+	if err != nil {
+		return false, err
+	}
+
+	// Parse major and minor versions
+	major, err := strconv.Atoi(serverVersion.Major)
+	if err != nil {
+		return false, fmt.Errorf("failed to parse major version: %w", err)
+	}
+
+	minor, err := strconv.Atoi(strings.TrimSuffix(serverVersion.Minor, "+"))
+	if err != nil {
+		return false, fmt.Errorf("failed to parse minor version: %w", err)
+	}
+
+	// Check if the server version meets or exceeds minMajor.minMinor
+	return major > minMajor || (major == minMajor && minor >= minMinor), nil
 }

From 76e26dc5d13a223b4e1075c96c9cf74eb7424a20 Mon Sep 17 00:00:00 2001
From: David <david@odigos.io>
Date: Fri, 15 Nov 2024 14:09:53 +0000
Subject: [PATCH 04/10] test

---
 .github/workflows/e2e.yaml | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml
index 6cbd99e52..eec69175e 100644
--- a/.github/workflows/e2e.yaml
+++ b/.github/workflows/e2e.yaml
@@ -65,7 +65,7 @@ jobs:
       fail-fast: false
       matrix:
         kube-version:
-          - "1.20.15"
+          - "1.23"
           - "1.30"
         test-scenario:
           - "multi-apps"
@@ -74,8 +74,8 @@ jobs:
           - "cli-upgrade"
           - "workload-lifecycle"
         include:
-          - kube-version: "1.20.15"
-            kind-image: "kindest/node:v1.20.15@sha256:a32bf55309294120616886b5338f95dd98a2f7231519c7dedcec32ba29699394"
+          - kube-version: "1.23"
+            kind-image: "kindest/node:v1.23.17@sha256:14d0a9a892b943866d7e6be119a06871291c517d279aedb816a4b4bc0ec0a5b3"
           - kube-version: "1.30"
             kind-image: "kindest/node:v1.30.0@sha256:047357ac0cfea04663786a612ba1eaba9702bef25227a794b52890dd8bcd692e"
     steps:

From 82640a80eede285e382c72b7e4b86c231d4eaa99 Mon Sep 17 00:00:00 2001
From: David <david@odigos.io>
Date: Fri, 15 Nov 2024 14:09:53 +0000
Subject: [PATCH 05/10] Use common k8sversion function

---
 .../controllers/collectorsgroup_controller.go |  4 +-
 .../controllers/datacollection/daemonset.go   | 19 +++---
 autoscaler/controllers/datacollection/root.go |  9 +--
 .../instrumentedapplication_controller.go     |  4 +-
 .../controllers/processor_controller.go       |  4 +-
 autoscaler/main.go                            | 68 ++++++-------------
 k8sutils/pkg/version/version.go               | 33 +++++++++
 7 files changed, 78 insertions(+), 63 deletions(-)
 create mode 100644 k8sutils/pkg/version/version.go

diff --git a/autoscaler/controllers/collectorsgroup_controller.go b/autoscaler/controllers/collectorsgroup_controller.go
index 14f12ccc2..fde7ad9ca 100644
--- a/autoscaler/controllers/collectorsgroup_controller.go
+++ b/autoscaler/controllers/collectorsgroup_controller.go
@@ -28,6 +28,7 @@ import (
 	"sigs.k8s.io/controller-runtime/pkg/log"
 
 	"k8s.io/apimachinery/pkg/runtime"
+	"k8s.io/apimachinery/pkg/util/version"
 	ctrl "sigs.k8s.io/controller-runtime"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 )
@@ -38,6 +39,7 @@ type CollectorsGroupReconciler struct {
 	Scheme               *runtime.Scheme
 	ImagePullSecrets     []string
 	OdigosVersion        string
+	K8sVersion           *version.Version
 	DisableNameProcessor bool
 	Config               *controllerconfig.ControllerConfig
 }
@@ -69,7 +71,7 @@ func (r *CollectorsGroupReconciler) Reconcile(ctx context.Context, req ctrl.Requ
 		return ctrl.Result{}, err
 	}
 
-	err = datacollection.Sync(ctx, r.Client, r.Scheme, r.ImagePullSecrets, r.OdigosVersion, r.DisableNameProcessor)
+	err = datacollection.Sync(ctx, r.Client, r.Scheme, r.ImagePullSecrets, r.OdigosVersion, r.K8sVersion, r.DisableNameProcessor)
 	if err != nil {
 		return ctrl.Result{}, err
 	}
diff --git a/autoscaler/controllers/datacollection/daemonset.go b/autoscaler/controllers/datacollection/daemonset.go
index fb3affb59..8509abbe2 100644
--- a/autoscaler/controllers/datacollection/daemonset.go
+++ b/autoscaler/controllers/datacollection/daemonset.go
@@ -12,6 +12,7 @@ import (
 	"github.com/odigos-io/odigos/autoscaler/controllers/common"
 	"github.com/odigos-io/odigos/autoscaler/controllers/datacollection/custom"
 	"github.com/odigos-io/odigos/autoscaler/utils"
+	"k8s.io/apimachinery/pkg/util/version"
 
 	"github.com/odigos-io/odigos/k8sutils/pkg/consts"
 	appsv1 "k8s.io/api/apps/v1"
@@ -49,7 +50,8 @@ type DelayManager struct {
 }
 
 // RunSyncDaemonSetWithDelayAndSkipNewCalls runs the function with the specified delay and skips new calls until the function execution is finished
-func (dm *DelayManager) RunSyncDaemonSetWithDelayAndSkipNewCalls(delay time.Duration, retries int, dests *odigosv1.DestinationList, collection *odigosv1.CollectorsGroup, ctx context.Context, c client.Client, scheme *runtime.Scheme, secrets []string, version string) {
+func (dm *DelayManager) RunSyncDaemonSetWithDelayAndSkipNewCalls(delay time.Duration, retries int, dests *odigosv1.DestinationList,
+	collection *odigosv1.CollectorsGroup, ctx context.Context, c client.Client, scheme *runtime.Scheme, secrets []string, version string, k8sVersion *version.Version) {
 	dm.mu.Lock()
 	defer dm.mu.Unlock()
 
@@ -78,7 +80,7 @@ func (dm *DelayManager) RunSyncDaemonSetWithDelayAndSkipNewCalls(delay time.Dura
 		}()
 
 		for i := 0; i < retries; i++ {
-			_, err = syncDaemonSet(ctx, dests, collection, c, scheme, secrets, version)
+			_, err = syncDaemonSet(ctx, dests, collection, c, scheme, secrets, version, k8sVersion)
 			if err == nil {
 				return
 			}
@@ -93,7 +95,7 @@ func (dm *DelayManager) finishProgress() {
 }
 
 func syncDaemonSet(ctx context.Context, dests *odigosv1.DestinationList, datacollection *odigosv1.CollectorsGroup,
-	c client.Client, scheme *runtime.Scheme, imagePullSecrets []string, odigosVersion string) (*appsv1.DaemonSet, error) {
+	c client.Client, scheme *runtime.Scheme, imagePullSecrets []string, odigosVersion string, k8sVersion *version.Version) (*appsv1.DaemonSet, error) {
 	logger := log.FromContext(ctx)
 
 	odigletDaemonsetPodSpec, err := getOdigletDaemonsetPodSpec(ctx, c, datacollection.Namespace)
@@ -114,7 +116,7 @@ func syncDaemonSet(ctx context.Context, dests *odigosv1.DestinationList, datacol
 		logger.Error(err, "Failed to get signals from otelcol config")
 		return nil, err
 	}
-	desiredDs, err := getDesiredDaemonSet(datacollection, otelcolConfigContent, scheme, imagePullSecrets, odigosVersion, odigletDaemonsetPodSpec)
+	desiredDs, err := getDesiredDaemonSet(datacollection, otelcolConfigContent, scheme, imagePullSecrets, odigosVersion, k8sVersion, odigletDaemonsetPodSpec)
 	if err != nil {
 		logger.Error(err, "Failed to get desired DaemonSet")
 		return nil, err
@@ -171,7 +173,7 @@ func getOdigletDaemonsetPodSpec(ctx context.Context, c client.Client, namespace
 }
 
 func getDesiredDaemonSet(datacollection *odigosv1.CollectorsGroup, configData string,
-	scheme *runtime.Scheme, imagePullSecrets []string, odigosVersion string,
+	scheme *runtime.Scheme, imagePullSecrets []string, odigosVersion string, k8sVersion *version.Version,
 	odigletDaemonsetPodSpec *corev1.PodSpec,
 ) (*appsv1.DaemonSet, error) {
 	// TODO(edenfed): add log volumes only if needed according to apps or dests
@@ -187,9 +189,8 @@ func getDesiredDaemonSet(datacollection *odigosv1.CollectorsGroup, configData st
 	rollingUpdate := &appsv1.RollingUpdateDaemonSet{
 		MaxUnavailable: &maxUnavailable,
 	}
-	cfg := ctrl.GetConfigOrDie()
-	versionSupported, err := isVersionSupported(cfg, 1, 22)
-	if err != nil && versionSupported {
+	// maxSurge was added to the Kubernetes api at version 1.21.alpha1, we want to be sure so we used 1.22 for the check, the fallback is without it
+	if k8sVersion != nil && k8sVersion.AtLeast(version.MustParse("1.22.0")) {
 		maxSurge := intstr.FromInt(0)
 		rollingUpdate.MaxSurge = &maxSurge
 	}
@@ -342,7 +343,7 @@ func getDesiredDaemonSet(datacollection *odigosv1.CollectorsGroup, configData st
 		}
 	}
 
-	err = ctrl.SetControllerReference(datacollection, desiredDs, scheme)
+	err := ctrl.SetControllerReference(datacollection, desiredDs, scheme)
 	if err != nil {
 		return nil, err
 	}
diff --git a/autoscaler/controllers/datacollection/root.go b/autoscaler/controllers/datacollection/root.go
index 0ad92b35e..80a6f11de 100644
--- a/autoscaler/controllers/datacollection/root.go
+++ b/autoscaler/controllers/datacollection/root.go
@@ -8,6 +8,7 @@ import (
 	"github.com/odigos-io/odigos/k8sutils/pkg/consts"
 	"github.com/odigos-io/odigos/k8sutils/pkg/env"
 	"k8s.io/apimachinery/pkg/runtime"
+	"k8s.io/apimachinery/pkg/util/version"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 	"sigs.k8s.io/controller-runtime/pkg/log"
 )
@@ -18,7 +19,7 @@ const (
 	syncDaemonsetRetry = 3
 )
 
-func Sync(ctx context.Context, c client.Client, scheme *runtime.Scheme, imagePullSecrets []string, odigosVersion string, disableNameProcessor bool) error {
+func Sync(ctx context.Context, c client.Client, scheme *runtime.Scheme, imagePullSecrets []string, odigosVersion string, k8sVersion *version.Version, disableNameProcessor bool) error {
 	logger := log.FromContext(ctx)
 
 	var instApps odigosv1.InstrumentedApplicationList
@@ -51,12 +52,12 @@ func Sync(ctx context.Context, c client.Client, scheme *runtime.Scheme, imagePul
 		return err
 	}
 
-	return syncDataCollection(&instApps, &dests, &processors, &dataCollectionCollectorGroup, ctx, c, scheme, imagePullSecrets, odigosVersion, disableNameProcessor)
+	return syncDataCollection(&instApps, &dests, &processors, &dataCollectionCollectorGroup, ctx, c, scheme, imagePullSecrets, odigosVersion, k8sVersion, disableNameProcessor)
 }
 
 func syncDataCollection(instApps *odigosv1.InstrumentedApplicationList, dests *odigosv1.DestinationList, processors *odigosv1.ProcessorList,
 	dataCollection *odigosv1.CollectorsGroup, ctx context.Context, c client.Client,
-	scheme *runtime.Scheme, imagePullSecrets []string, odigosVersion string, disableNameProcessor bool) error {
+	scheme *runtime.Scheme, imagePullSecrets []string, odigosVersion string, k8sVersion *version.Version, disableNameProcessor bool) error {
 	logger := log.FromContext(ctx)
 	logger.V(0).Info("Syncing data collection")
 
@@ -66,7 +67,7 @@ func syncDataCollection(instApps *odigosv1.InstrumentedApplicationList, dests *o
 		return err
 	}
 
-	dm.RunSyncDaemonSetWithDelayAndSkipNewCalls(time.Duration(env.GetSyncDaemonSetDelay())*time.Second, syncDaemonsetRetry, dests, dataCollection, ctx, c, scheme, imagePullSecrets, odigosVersion)
+	dm.RunSyncDaemonSetWithDelayAndSkipNewCalls(time.Duration(env.GetSyncDaemonSetDelay())*time.Second, syncDaemonsetRetry, dests, dataCollection, ctx, c, scheme, imagePullSecrets, odigosVersion, k8sVersion)
 
 	return nil
 }
diff --git a/autoscaler/controllers/instrumentedapplication_controller.go b/autoscaler/controllers/instrumentedapplication_controller.go
index 25e21793d..df97a49b9 100644
--- a/autoscaler/controllers/instrumentedapplication_controller.go
+++ b/autoscaler/controllers/instrumentedapplication_controller.go
@@ -22,6 +22,7 @@ import (
 	odigosv1 "github.com/odigos-io/odigos/api/odigos/v1alpha1"
 	"github.com/odigos-io/odigos/autoscaler/controllers/datacollection"
 	"k8s.io/apimachinery/pkg/runtime"
+	"k8s.io/apimachinery/pkg/util/version"
 	ctrl "sigs.k8s.io/controller-runtime"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 	"sigs.k8s.io/controller-runtime/pkg/log"
@@ -33,6 +34,7 @@ type InstrumentedApplicationReconciler struct {
 	Scheme               *runtime.Scheme
 	ImagePullSecrets     []string
 	OdigosVersion        string
+	K8sVersion           *version.Version
 	DisableNameProcessor bool
 }
 
@@ -51,7 +53,7 @@ type InstrumentedApplicationReconciler struct {
 func (r *InstrumentedApplicationReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
 	logger := log.FromContext(ctx)
 	logger.V(0).Info("Reconciling InstrumentedApps")
-	err := datacollection.Sync(ctx, r.Client, r.Scheme, r.ImagePullSecrets, r.OdigosVersion, r.DisableNameProcessor)
+	err := datacollection.Sync(ctx, r.Client, r.Scheme, r.ImagePullSecrets, r.OdigosVersion, r.K8sVersion, r.DisableNameProcessor)
 	if err != nil {
 		return ctrl.Result{}, err
 	}
diff --git a/autoscaler/controllers/processor_controller.go b/autoscaler/controllers/processor_controller.go
index 891f14f28..958e99df8 100644
--- a/autoscaler/controllers/processor_controller.go
+++ b/autoscaler/controllers/processor_controller.go
@@ -8,6 +8,7 @@ import (
 	"github.com/odigos-io/odigos/autoscaler/controllers/datacollection"
 	"github.com/odigos-io/odigos/autoscaler/controllers/gateway"
 	"k8s.io/apimachinery/pkg/runtime"
+	"k8s.io/apimachinery/pkg/util/version"
 	ctrl "sigs.k8s.io/controller-runtime"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 	"sigs.k8s.io/controller-runtime/pkg/log"
@@ -18,6 +19,7 @@ type ProcessorReconciler struct {
 	Scheme               *runtime.Scheme
 	ImagePullSecrets     []string
 	OdigosVersion        string
+	K8sVersion           *version.Version
 	DisableNameProcessor bool
 	Config               *controllerconfig.ControllerConfig
 }
@@ -32,7 +34,7 @@ func (r *ProcessorReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
 		return ctrl.Result{}, err
 	}
 
-	err = datacollection.Sync(ctx, r.Client, r.Scheme, r.ImagePullSecrets, r.OdigosVersion, r.DisableNameProcessor)
+	err = datacollection.Sync(ctx, r.Client, r.Scheme, r.ImagePullSecrets, r.OdigosVersion, r.K8sVersion, r.DisableNameProcessor)
 	if err != nil {
 		return ctrl.Result{}, err
 	}
diff --git a/autoscaler/main.go b/autoscaler/main.go
index 68a1aafb6..20dfcec67 100644
--- a/autoscaler/main.go
+++ b/autoscaler/main.go
@@ -19,14 +19,13 @@ package main
 import (
 	"context"
 	"flag"
-	"fmt"
 	"os"
-	"strconv"
 	"strings"
 
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
 
 	"github.com/odigos-io/odigos/k8sutils/pkg/env"
+	odigosver "github.com/odigos-io/odigos/k8sutils/pkg/version"
 
 	corev1 "k8s.io/api/core/v1"
 
@@ -47,9 +46,8 @@ import (
 	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/apimachinery/pkg/types"
 	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
-	"k8s.io/client-go/discovery"
+	"k8s.io/apimachinery/pkg/util/version"
 	clientgoscheme "k8s.io/client-go/kubernetes/scheme"
-	"k8s.io/client-go/rest"
 	ctrl "sigs.k8s.io/controller-runtime"
 	"sigs.k8s.io/controller-runtime/pkg/healthz"
 	ctrlzap "sigs.k8s.io/controller-runtime/pkg/log/zap"
@@ -88,7 +86,6 @@ func main() {
 	var probeAddr string
 	var imagePullSecretsString string
 	var imagePullSecrets []string
-	odigosVersion := os.Getenv("ODIGOS_VERSION")
 
 	flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.")
 	flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.")
@@ -99,9 +96,15 @@ func main() {
 		"The image pull secrets to use for the collectors created by autoscaler")
 	flag.StringVar(&nameutils.ImagePrefix, "image-prefix", "", "The image prefix to use for the collectors created by autoscaler")
 
+	odigosVersion := os.Getenv("ODIGOS_VERSION")
 	if odigosVersion == "" {
 		flag.StringVar(&odigosVersion, "version", "", "for development purposes only")
 	}
+	// Get k8s version
+	k8sVersion, err := odigosver.GetKubernetesVersion()
+	if err != nil {
+		setupLog.Error(err, "unable to get Kubernetes version, continuing with default oldest supported version")
+	}
 
 	opts := ctrlzap.Options{
 		Development: true,
@@ -131,12 +134,6 @@ func main() {
 	clusterCollectorLabelSelector := labels.Set(gateway.ClusterCollectorGateway).AsSelector()
 
 	cfg := ctrl.GetConfigOrDie()
-	// Determine if we need to use a non-caching client based on the Kubernetes version, version <1.23 has issues when using caching client
-	useNonCachingClient, err := shouldUseNonCachingClient(cfg)
-	if err != nil {
-		setupLog.Error(err, "unable to determine Kubernetes version")
-		os.Exit(1)
-	}
 	mgr, err := ctrl.NewManager(cfg, ctrl.Options{
 		Scheme: scheme,
 		Metrics: metricsserver.Options{
@@ -174,7 +171,16 @@ func main() {
 	}
 	// Ver < 1.23
 	var migrationClient client.Client
-	if useNonCachingClient {
+	// Determine if we need to use a non-caching client based on the Kubernetes version, version <1.23 has issues when using caching client
+
+	if k8sVersion != nil && k8sVersion.GreaterThan(version.MustParse("v1.23")) {
+		// Use the cached client for versions >= 1.23
+		err = MigrateCollectorsWorkloadToNewLabels(context.Background(), mgr.GetClient(), odigosNs)
+		if err != nil {
+			setupLog.Error(err, "unable to migrate collectors workload to new labels")
+			os.Exit(1)
+		}
+	} else {
 		// Create a non-caching client for versions < 1.23
 		migrationClient, err = client.New(cfg, client.Options{Scheme: scheme})
 		if err != nil {
@@ -187,13 +193,6 @@ func main() {
 			setupLog.Error(err, "legacy unable to migrate collectors workload to new labels")
 			os.Exit(1)
 		}
-	} else {
-		// Use the cached client for versions >= 1.23
-		err = MigrateCollectorsWorkloadToNewLabels(context.Background(), mgr.GetClient(), odigosNs)
-		if err != nil {
-			setupLog.Error(err, "unable to migrate collectors workload to new labels")
-			os.Exit(1)
-		}
 	}
 
 	// The name processor is used to transform device ids injected with the virtual device,
@@ -222,6 +221,7 @@ func main() {
 		Scheme:               mgr.GetScheme(),
 		ImagePullSecrets:     imagePullSecrets,
 		OdigosVersion:        odigosVersion,
+		K8sVersion:           k8sVersion,
 		DisableNameProcessor: disableNameProcessor,
 		Config:               config,
 	}).SetupWithManager(mgr); err != nil {
@@ -233,6 +233,7 @@ func main() {
 		Scheme:               mgr.GetScheme(),
 		ImagePullSecrets:     imagePullSecrets,
 		OdigosVersion:        odigosVersion,
+		K8sVersion:           k8sVersion,
 		DisableNameProcessor: disableNameProcessor,
 		Config:               config,
 	}).SetupWithManager(mgr); err != nil {
@@ -244,6 +245,7 @@ func main() {
 		Scheme:               mgr.GetScheme(),
 		ImagePullSecrets:     imagePullSecrets,
 		OdigosVersion:        odigosVersion,
+		K8sVersion:           k8sVersion,
 		DisableNameProcessor: disableNameProcessor,
 	}).SetupWithManager(mgr); err != nil {
 		setupLog.Error(err, "unable to create controller", "controller", "InstrumentedApplication")
@@ -322,31 +324,3 @@ func isMetricsServerInstalled(mgr ctrl.Manager, logger logr.Logger) bool {
 	logger.V(0).Info("Metrics server found")
 	return true
 }
-
-// Kubernetes version <1.23 has issues when using caching client and also DeleteAllOf is not supported in versions <1.23
-// so we need to use legacy delete for versions <1.23
-func shouldUseNonCachingClient(cfg *rest.Config) (bool, error) {
-	discoveryClient, err := discovery.NewDiscoveryClientForConfig(cfg)
-	if err != nil {
-		return false, err
-	}
-
-	serverVersion, err := discoveryClient.ServerVersion()
-	if err != nil {
-		return false, err
-	}
-
-	// Parse the major and minor versions
-	major, err := strconv.Atoi(serverVersion.Major)
-	if err != nil {
-		return false, fmt.Errorf("failed to parse major version: %w", err)
-	}
-
-	minor, err := strconv.Atoi(strings.TrimSuffix(serverVersion.Minor, "+"))
-	if err != nil {
-		return false, fmt.Errorf("failed to parse minor version: %w", err)
-	}
-
-	// Use non-caching client if the version is less than 1.23
-	return major < 1 || (major == 1 && minor < 23), nil
-}
diff --git a/k8sutils/pkg/version/version.go b/k8sutils/pkg/version/version.go
new file mode 100644
index 000000000..d2f907f66
--- /dev/null
+++ b/k8sutils/pkg/version/version.go
@@ -0,0 +1,33 @@
+package version
+
+import (
+	"k8s.io/apimachinery/pkg/util/version"
+	"k8s.io/client-go/discovery"
+	"k8s.io/client-go/rest"
+)
+
+// GetKubernetesVersion returns the Kubernetes version of the cluster
+// This util function is intended to be called once during the initialization.
+// Do not call this from reconcile or hot path.
+func GetKubernetesVersion() (*version.Version, error) {
+	// Create a Kubernetes REST config directly
+	cfg, err := rest.InClusterConfig()
+	if err != nil {
+		return nil, err
+	}
+
+	// Create a discovery client using the config
+	discoveryClient, err := discovery.NewDiscoveryClientForConfig(cfg)
+	if err != nil {
+		return nil, err
+	}
+
+	// Retrieve the server version
+	serverVersion, err := discoveryClient.ServerVersion()
+	if err != nil {
+		return nil, err
+	}
+
+	// Parse and return the version
+	return version.Parse(serverVersion.String())
+}

From 989030b08c142cf5d12a6fe5152713a2b063f8e5 Mon Sep 17 00:00:00 2001
From: David <david@odigos.io>
Date: Fri, 15 Nov 2024 14:09:53 +0000
Subject: [PATCH 06/10] Use util function to get k8s version

---
 cli/pkg/kube/client.go | 39 ++++++++-------------------------------
 1 file changed, 8 insertions(+), 31 deletions(-)

diff --git a/cli/pkg/kube/client.go b/cli/pkg/kube/client.go
index 319540e3b..c1f9d7746 100644
--- a/cli/pkg/kube/client.go
+++ b/cli/pkg/kube/client.go
@@ -5,9 +5,9 @@ import (
 	"fmt"
 	"os"
 	"strconv"
-	"strings"
 
 	k8sutils "github.com/odigos-io/odigos/k8sutils/pkg/client"
+	odigosver "github.com/odigos-io/odigos/k8sutils/pkg/version"
 
 	appsv1 "k8s.io/api/apps/v1"
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
@@ -15,6 +15,7 @@ import (
 	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/apimachinery/pkg/selection"
 	k8stypes "k8s.io/apimachinery/pkg/types"
+	"k8s.io/apimachinery/pkg/util/version"
 	"sigs.k8s.io/yaml"
 
 	"github.com/odigos-io/odigos/api/generated/odigos/clientset/versioned/typed/odigos/v1alpha1"
@@ -22,12 +23,10 @@ import (
 	"github.com/spf13/cobra"
 	apiextensionsclient "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
 	k8slabels "k8s.io/apimachinery/pkg/labels"
-	"k8s.io/client-go/discovery"
 	"k8s.io/client-go/dynamic"
 	"k8s.io/client-go/kubernetes"
 	_ "k8s.io/client-go/plugin/pkg/client/auth"
 	"k8s.io/client-go/rest"
-	ctrl "sigs.k8s.io/controller-runtime"
 )
 
 type Client struct {
@@ -200,9 +199,12 @@ func (c *Client) DeleteOldOdigosSystemObjects(ctx context.Context, resourceAndNa
 	labelSelector := k8slabels.NewSelector().Add(*systemObject).Add(*notLatestVersion).String()
 	resource := resourceAndNamespace.Resource
 	ns := resourceAndNamespace.Namespace
-	cfg := ctrl.GetConfigOrDie()
-	versionSupported, err := isVersionSupported(cfg, 1, 23)
-	if err != nil && versionSupported {
+	k8sVersion, err := odigosver.GetKubernetesVersion()
+	if err != nil {
+		fmt.Printf("DeleteOldOdigosSystemObjects failed to get k8s version, proceeding.. :%v", err)
+	}
+	// DeleteCollection is only available in k8s 1.23 and above, for older versions we need to list and delete each resource
+	if k8sVersion != nil && k8sVersion.GreaterThan(version.MustParse("1.23")) {
 		return c.Dynamic.Resource(resource).Namespace(ns).DeleteCollection(ctx, metav1.DeleteOptions{}, metav1.ListOptions{
 			LabelSelector: labelSelector,
 		})
@@ -225,28 +227,3 @@ func (c *Client) DeleteOldOdigosSystemObjects(ctx context.Context, resourceAndNa
 	}
 	return nil
 }
-func isVersionSupported(cfg *rest.Config, minMajor int, minMinor int) (bool, error) {
-	discoveryClient, err := discovery.NewDiscoveryClientForConfig(cfg)
-	if err != nil {
-		return false, err
-	}
-
-	serverVersion, err := discoveryClient.ServerVersion()
-	if err != nil {
-		return false, err
-	}
-
-	// Parse major and minor versions
-	major, err := strconv.Atoi(serverVersion.Major)
-	if err != nil {
-		return false, fmt.Errorf("failed to parse major version: %w", err)
-	}
-
-	minor, err := strconv.Atoi(strings.TrimSuffix(serverVersion.Minor, "+"))
-	if err != nil {
-		return false, fmt.Errorf("failed to parse minor version: %w", err)
-	}
-
-	// Check if the server version meets or exceeds minMajor.minMinor
-	return major > minMajor || (major == minMajor && minor >= minMinor), nil
-}

From 96b49589036b5437e083327693467e5962eff76d Mon Sep 17 00:00:00 2001
From: David <david@odigos.io>
Date: Fri, 15 Nov 2024 14:09:53 +0000
Subject: [PATCH 07/10] Cleanup

---
 .../controllers/datacollection/daemonset.go   | 30 -------------------
 1 file changed, 30 deletions(-)

diff --git a/autoscaler/controllers/datacollection/daemonset.go b/autoscaler/controllers/datacollection/daemonset.go
index 8509abbe2..1d93b5d9a 100644
--- a/autoscaler/controllers/datacollection/daemonset.go
+++ b/autoscaler/controllers/datacollection/daemonset.go
@@ -3,8 +3,6 @@ package datacollection
 import (
 	"context"
 	"fmt"
-	"strconv"
-	"strings"
 	"sync"
 	"time"
 
@@ -22,8 +20,6 @@ import (
 	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/apimachinery/pkg/types"
 	"k8s.io/apimachinery/pkg/util/intstr"
-	"k8s.io/client-go/discovery"
-	"k8s.io/client-go/rest"
 	ctrl "sigs.k8s.io/controller-runtime"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 	"sigs.k8s.io/controller-runtime/pkg/log"
@@ -380,29 +376,3 @@ func patchDaemonSet(existing *appsv1.DaemonSet, desired *appsv1.DaemonSet, ctx c
 
 	return updated, nil
 }
-
-func isVersionSupported(cfg *rest.Config, minMajor int, minMinor int) (bool, error) {
-	discoveryClient, err := discovery.NewDiscoveryClientForConfig(cfg)
-	if err != nil {
-		return false, err
-	}
-
-	serverVersion, err := discoveryClient.ServerVersion()
-	if err != nil {
-		return false, err
-	}
-
-	// Parse major and minor versions
-	major, err := strconv.Atoi(serverVersion.Major)
-	if err != nil {
-		return false, fmt.Errorf("failed to parse major version: %w", err)
-	}
-
-	minor, err := strconv.Atoi(strings.TrimSuffix(serverVersion.Minor, "+"))
-	if err != nil {
-		return false, fmt.Errorf("failed to parse minor version: %w", err)
-	}
-
-	// Check if the server version meets or exceeds minMajor.minMinor
-	return major > minMajor || (major == minMajor && minor >= minMinor), nil
-}

From 2bef0c97ba195cca47b71e4585536a8b13497251 Mon Sep 17 00:00:00 2001
From: David <david@odigos.io>
Date: Fri, 15 Nov 2024 14:09:53 +0000
Subject: [PATCH 08/10] Add kube ver 1.20.15 to e2e

---
 .github/workflows/e2e.yaml | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml
index eec69175e..dbaaba21e 100644
--- a/.github/workflows/e2e.yaml
+++ b/.github/workflows/e2e.yaml
@@ -65,6 +65,7 @@ jobs:
       fail-fast: false
       matrix:
         kube-version:
+          - "1.20.15"
           - "1.23"
           - "1.30"
         test-scenario:
@@ -74,6 +75,8 @@ jobs:
           - "cli-upgrade"
           - "workload-lifecycle"
         include:
+          - kube-version: "1.20.15"
+            kind-image: "kindest/node:v1.20.15@sha256:a32bf55309294120616886b5338f95dd98a2f7231519c7dedcec32ba29699394"
           - kube-version: "1.23"
             kind-image: "kindest/node:v1.23.17@sha256:14d0a9a892b943866d7e6be119a06871291c517d279aedb816a4b4bc0ec0a5b3"
           - kube-version: "1.30"

From 21a86cffe7478af5af0aac522d50fc1fc95029c2 Mon Sep 17 00:00:00 2001
From: David <david@odigos.io>
Date: Fri, 15 Nov 2024 14:09:53 +0000
Subject: [PATCH 09/10] Code review

---
 autoscaler/main.go      | 15 ++-------------
 autoscaler/migration.go | 39 ---------------------------------------
 cli/cmd/install.go      |  3 ++-
 cli/go.mod              | 12 +-----------
 cli/go.sum              | 22 ----------------------
 5 files changed, 5 insertions(+), 86 deletions(-)

diff --git a/autoscaler/main.go b/autoscaler/main.go
index 20dfcec67..ee0126dcd 100644
--- a/autoscaler/main.go
+++ b/autoscaler/main.go
@@ -173,6 +173,8 @@ func main() {
 	var migrationClient client.Client
 	// Determine if we need to use a non-caching client based on the Kubernetes version, version <1.23 has issues when using caching client
 
+	// The labaling was for ver 1.0.91, migration is not releavant for old k8s versions which couln't run.
+	// This is the reason we skip it for versions < 1.23 (Also, versions < 1.23 require a non-caching client and API chane)
 	if k8sVersion != nil && k8sVersion.GreaterThan(version.MustParse("v1.23")) {
 		// Use the cached client for versions >= 1.23
 		err = MigrateCollectorsWorkloadToNewLabels(context.Background(), mgr.GetClient(), odigosNs)
@@ -180,19 +182,6 @@ func main() {
 			setupLog.Error(err, "unable to migrate collectors workload to new labels")
 			os.Exit(1)
 		}
-	} else {
-		// Create a non-caching client for versions < 1.23
-		migrationClient, err = client.New(cfg, client.Options{Scheme: scheme})
-		if err != nil {
-			setupLog.Error(err, "unable to create non-caching client for migration")
-			os.Exit(1)
-		}
-		// Migrate collectors workload to new labels using old API
-		err = OldVerKubernetesMigrateCollectorsWorkloadToNewLabels(context.Background(), migrationClient, odigosNs)
-		if err != nil {
-			setupLog.Error(err, "legacy unable to migrate collectors workload to new labels")
-			os.Exit(1)
-		}
 	}
 
 	// The name processor is used to transform device ids injected with the virtual device,
diff --git a/autoscaler/migration.go b/autoscaler/migration.go
index 7a3f6a8f3..b53b3d32c 100644
--- a/autoscaler/migration.go
+++ b/autoscaler/migration.go
@@ -50,42 +50,3 @@ func MigrateCollectorsWorkloadToNewLabels(ctx context.Context, c client.Client,
 	return nil
 
 }
-func OldVerKubernetesMigrateCollectorsWorkloadToNewLabels(ctx context.Context, c client.Client, ns string) error {
-	// Use the legacy method for Kubernetes versions < 1.23
-
-	// List and delete Deployments with the label "odigos.io/collector": "true"
-	preV1_0_91LabelSelectorGateway := client.MatchingLabels{"odigos.io/collector": "true"}
-	var deployments appsv1.DeploymentList
-	if err := c.List(ctx, &deployments, client.InNamespace(ns), preV1_0_91LabelSelectorGateway); err != nil {
-		return err
-	}
-	for _, deployment := range deployments.Items {
-		if err := c.Delete(ctx, &deployment); err != nil {
-			return err
-		}
-	}
-
-	// List and delete Services with the label "odigos.io/collector": "true"
-	var services corev1.ServiceList
-	if err := c.List(ctx, &services, client.InNamespace(ns), preV1_0_91LabelSelectorGateway); err != nil {
-		return err
-	}
-	for _, service := range services.Items {
-		if err := c.Delete(ctx, &service); err != nil {
-			return err
-		}
-	}
-
-	// List and delete DaemonSets with the label "odigos.io/data-collection": "true"
-	preV1_0_91LabelSelectorNodeCollector := client.MatchingLabels{"odigos.io/data-collection": "true"}
-	var daemonSets appsv1.DaemonSetList
-	if err := c.List(ctx, &daemonSets, client.InNamespace(ns), preV1_0_91LabelSelectorNodeCollector); err != nil {
-		return err
-	}
-	for _, daemonSet := range daemonSets.Items {
-		if err := c.Delete(ctx, &daemonSet); err != nil {
-			return err
-		}
-	}
-	return nil
-}
diff --git a/cli/cmd/install.go b/cli/cmd/install.go
index 05f36c705..447f20da6 100644
--- a/cli/cmd/install.go
+++ b/cli/cmd/install.go
@@ -82,6 +82,7 @@ This command will install k8s components that will auto-instrument your applicat
 		details, err := autodetect.DetectK8SClusterDetails(ctx, kc, client)
 		if !errors.Is(err, autodetect.ErrCannotDetectClusterKind) {
 			autodetect.CurrentKubernetesVersion.Kind = details.Kind
+			fmt.Printf("Detected cluster: Kubernetes kind: %s\n", details.Kind)
 		} else {
 			fmt.Println("Unknown Kubernetes cluster detected, proceeding with installation")
 		}
@@ -92,7 +93,7 @@ This command will install k8s components that will auto-instrument your applicat
 				fmt.Printf("\033[31mERROR\033[0m Odigos requires Kubernetes version %s or higher but found %s, aborting\n", minK8SVersionForInstallation.String(), details.K8SVersion.String())
 				os.Exit(1)
 			}
-			fmt.Printf("Detected cluster: %s Kubernetes version: %s\n", details.Kind, details.K8SVersion.String())
+			fmt.Printf("Detected cluster: Kubernetes version: %s\n", details.K8SVersion.String())
 		} else {
 			fmt.Println("Unknown Kubernetes version detected, proceeding with installation")
 		}
diff --git a/cli/go.mod b/cli/go.mod
index 130f1aa6c..0bdf04b91 100644
--- a/cli/go.mod
+++ b/cli/go.mod
@@ -15,32 +15,22 @@ require (
 	k8s.io/apiextensions-apiserver v0.31.0
 	k8s.io/apimachinery v0.31.0
 	k8s.io/client-go v0.31.0
-	sigs.k8s.io/controller-runtime v0.19.0
 	sigs.k8s.io/yaml v1.4.0
 )
 
 require (
-	github.com/beorn7/perks v1.0.1 // indirect
-	github.com/cespare/xxhash/v2 v2.3.0 // indirect
 	github.com/fatih/color v1.16.0 // indirect
-	github.com/fsnotify/fsnotify v1.7.0 // indirect
 	github.com/fxamacker/cbor/v2 v2.7.0 // indirect
 	github.com/goccy/go-yaml v1.11.3 // indirect
-	github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
 	github.com/gorilla/websocket v1.5.1 // indirect
 	github.com/mattn/go-colorable v0.1.13 // indirect
 	github.com/mattn/go-isatty v0.0.20 // indirect
 	github.com/moby/spdystream v0.4.0 // indirect
 	github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
-	github.com/prometheus/client_golang v1.19.1 // indirect
-	github.com/prometheus/client_model v0.6.1 // indirect
-	github.com/prometheus/common v0.55.0 // indirect
-	github.com/prometheus/procfs v0.15.1 // indirect
 	github.com/spf13/pflag v1.0.5 // indirect
 	github.com/x448/float16 v0.8.4 // indirect
-	golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect
 	golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
-	gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
+	sigs.k8s.io/controller-runtime v0.19.0 // indirect
 	sigs.k8s.io/gateway-api v1.1.0 // indirect
 )
 
diff --git a/cli/go.sum b/cli/go.sum
index d36e0ca77..c67c4944a 100644
--- a/cli/go.sum
+++ b/cli/go.sum
@@ -1,11 +1,7 @@
 github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
 github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
-github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
-github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
 github.com/cert-manager/cert-manager v1.15.3 h1:/u9T0griwd5MegPfWbB7v0KcVcT9OJrEvPNhc9tl7xQ=
 github.com/cert-manager/cert-manager v1.15.3/go.mod h1:stBge/DTvrhfQMB/93+Y62s+gQgZBsfL1o0C/4AL/mI=
-github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
-github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
 github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -13,14 +9,10 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1
 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/emicklei/go-restful/v3 v3.12.0 h1:y2DdzBAURM29NFF94q6RaY4vjIH1rtwDapwQtU84iWk=
 github.com/emicklei/go-restful/v3 v3.12.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
-github.com/evanphx/json-patch v5.9.0+incompatible h1:fBXyNpNMuTTDdquAq/uisOr2lShz4oaXpDTX2bLe7ls=
-github.com/evanphx/json-patch v5.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
 github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg=
 github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ=
 github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
 github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
-github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
-github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
 github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
 github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
 github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
@@ -45,8 +37,6 @@ github.com/goccy/go-yaml v1.11.3 h1:B3W9IdWbvrUu2OYQGwvU1nZtvMQJPBKgBUuweJjLj6I=
 github.com/goccy/go-yaml v1.11.3/go.mod h1:wKnAMd44+9JAAnGQpWVEgBzGt3YuTaQ4uXoHvE4m7WU=
 github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
 github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
-github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
-github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
 github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
 github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I=
@@ -108,14 +98,6 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
 github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE=
-github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho=
-github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
-github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
-github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc=
-github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8=
-github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
-github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
 github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
 github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
 github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
@@ -137,8 +119,6 @@ go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw=
 go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8=
 go.opentelemetry.io/otel/trace v1.29.0 h1:J/8ZNK4XgR7a21DZUAsbF8pZ5Jcw1VhACmnYt39JTi4=
 go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ=
-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=
 go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
 go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
@@ -190,8 +170,6 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU=
 golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
-gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw=
-gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
 google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
 google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

From 902a5f84075f0db213819082a18156fc82d95bd2 Mon Sep 17 00:00:00 2001
From: David <david@odigos.io>
Date: Fri, 15 Nov 2024 14:09:53 +0000
Subject: [PATCH 10/10] fix

---
 autoscaler/main.go | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/autoscaler/main.go b/autoscaler/main.go
index ee0126dcd..e33ca39cc 100644
--- a/autoscaler/main.go
+++ b/autoscaler/main.go
@@ -169,9 +169,6 @@ func main() {
 		setupLog.Error(err, "unable to start manager")
 		os.Exit(1)
 	}
-	// Ver < 1.23
-	var migrationClient client.Client
-	// Determine if we need to use a non-caching client based on the Kubernetes version, version <1.23 has issues when using caching client
 
 	// The labaling was for ver 1.0.91, migration is not releavant for old k8s versions which couln't run.
 	// This is the reason we skip it for versions < 1.23 (Also, versions < 1.23 require a non-caching client and API chane)