From 60d3d404c520dec0ee9cd26d52478b20e23cc301 Mon Sep 17 00:00:00 2001 From: Gianluca Mardente Date: Mon, 1 Jun 2026 15:02:15 +0200 Subject: [PATCH] (feat) telemetry: add management cluster kubernetes version and provider --- go.mod | 2 +- go.sum | 4 +- internal/telemetry/report.go | 109 ++++++++++++++++++++++++++++-- test/pullmode-sveltosapplier.yaml | 2 +- 4 files changed, 107 insertions(+), 10 deletions(-) diff --git a/go.mod b/go.mod index 2aa5df8e..cd14e4b7 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( github.com/onsi/ginkgo/v2 v2.29.0 github.com/onsi/gomega v1.41.0 github.com/pkg/errors v0.9.1 - github.com/projectsveltos/libsveltos v1.10.1-0.20260529122402-5f1c02139fd0 + github.com/projectsveltos/libsveltos v1.10.1-0.20260601130048-ace88648a3f5 github.com/prometheus/client_golang v1.23.2 github.com/robfig/cron v1.2.0 github.com/spf13/pflag v1.0.10 diff --git a/go.sum b/go.sum index 8275b59e..2fe7780e 100644 --- a/go.sum +++ b/go.sum @@ -273,8 +273,8 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/poy/onpar v1.1.2 h1:QaNrNiZx0+Nar5dLgTVp5mXkyoVFIbepjyEoGSnhbAY= github.com/poy/onpar v1.1.2/go.mod h1:6X8FLNoxyr9kkmnlqpK6LSoiOtrO6MICtWwEuWkLjzg= -github.com/projectsveltos/libsveltos v1.10.1-0.20260529122402-5f1c02139fd0 h1:MK7tWuz0RKKJS6SITR9fHsRXH9rRq4uYN4QmQbtHehc= -github.com/projectsveltos/libsveltos v1.10.1-0.20260529122402-5f1c02139fd0/go.mod h1:AzKBiyMTL3KSTLYMii5QdR3ieWyUKBHZCMFWIVCfm6A= +github.com/projectsveltos/libsveltos v1.10.1-0.20260601130048-ace88648a3f5 h1:eRrg+zo7Gna3AGvunD/r4XCQxwkNUyQ0xzesEF+6Ayo= +github.com/projectsveltos/libsveltos v1.10.1-0.20260601130048-ace88648a3f5/go.mod h1:AzKBiyMTL3KSTLYMii5QdR3ieWyUKBHZCMFWIVCfm6A= github.com/projectsveltos/lua-utils/glua-json v0.0.0-20251212200258-2b3cdcb7c0f5 h1:khnc+994UszxZYu69J+R5FKiLA/Nk1JQj0EYAkwTWz0= github.com/projectsveltos/lua-utils/glua-json v0.0.0-20251212200258-2b3cdcb7c0f5/go.mod h1:yVL8KQFa9tmcxgwl9nwIMtKgtmIVC1zaFRSCfOwYvPY= github.com/projectsveltos/lua-utils/glua-runes v0.0.0-20251212200258-2b3cdcb7c0f5 h1:YbsebwRwTRhV8QacvEAdFqxcxHdeu7JTVtsBovbkgos= diff --git a/internal/telemetry/report.go b/internal/telemetry/report.go index c2e57758..492e837e 100644 --- a/internal/telemetry/report.go +++ b/internal/telemetry/report.go @@ -22,6 +22,7 @@ import ( "encoding/json" "fmt" "net/http" + "strings" "sync" "time" @@ -30,6 +31,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/discovery" "k8s.io/client-go/dynamic" "k8s.io/client-go/rest" clusterv1 "sigs.k8s.io/cluster-api/api/core/v1beta2" @@ -60,6 +62,10 @@ var ( const ( contentTypeJSON = "application/json" domain = "http://telemetry.projectsveltos.io/" + + providerEKS = "eks" + providerGKE = "gke" + providerAKS = "aks" ) func StartCollecting(ctx context.Context, config *rest.Config, c client.Client, @@ -161,7 +167,7 @@ func (m *instance) collectData(ctx context.Context, uuid string) (*libsveltostel } } - clusterProfiles, profiles, clusterSummaries, err := m.collectConfigurationData(ctx) + clusterProfiles, profiles, clusterSummaries, clusterPromotions, err := m.collectConfigurationData(ctx) if err != nil { logger.V(logs.LogInfo).Info(fmt.Sprintf("failed to collect Sveltos configuration data: %v", err)) return nil, err @@ -169,6 +175,7 @@ func (m *instance) collectData(ctx context.Context, uuid string) (*libsveltostel data.ClusterProfiles = clusterProfiles data.Profiles = profiles data.ClusterSummaries = clusterSummaries + data.ClusterPromotions = clusterPromotions et, chc, err := m.collectEventData(ctx) if err != nil { @@ -178,34 +185,46 @@ func (m *instance) collectData(ctx context.Context, uuid string) (*libsveltostel data.ClusterHealthChecks = chc } + provider, k8sVersion, nodeCount := m.collectManagementClusterInfo(ctx) + data.ManagementClusterProvider = provider + data.KubernetesVersion = k8sVersion + data.ManagementClusterNodes = nodeCount + return &data, nil } -func (m *instance) collectConfigurationData(ctx context.Context) (cpInstances, pInstances, csInstances int, err error) { +func (m *instance) collectConfigurationData(ctx context.Context) (cpInstances, pInstances, csInstances, promotionInstances int, err error) { logger := log.FromContext(ctx) var clusterProfiles configv1beta1.ClusterProfileList if err = m.List(ctx, &clusterProfiles); err != nil { logger.V(logs.LogInfo).Info(fmt.Sprintf("failed to collect clusterProfiles: %v", err)) - return + return 0, 0, 0, 0, err } cpInstances = len(clusterProfiles.Items) var profiles configv1beta1.ProfileList if err = m.List(ctx, &profiles); err != nil { logger.V(logs.LogInfo).Info(fmt.Sprintf("failed to collect Profiles: %v", err)) - return + return 0, 0, 0, 0, err } pInstances = len(profiles.Items) var clusterSummaries configv1beta1.ClusterSummaryList if err = m.List(ctx, &clusterSummaries); err != nil { logger.V(logs.LogInfo).Info(fmt.Sprintf("failed to collect ClusterSummaries: %v", err)) - return + return 0, 0, 0, 0, err } csInstances = len(clusterSummaries.Items) - return + var clusterPromotions configv1beta1.ClusterPromotionList + if err = m.List(ctx, &clusterPromotions); err != nil { + logger.V(logs.LogInfo).Info(fmt.Sprintf("failed to collect ClusterPromotions: %v", err)) + return cpInstances, pInstances, csInstances, 0, nil + } + promotionInstances = len(clusterPromotions.Items) + + return cpInstances, pInstances, csInstances, promotionInstances, nil } func (m *instance) collectEventData(ctx context.Context) (eventTriggers, clusterHealthChecks int, err error) { @@ -247,6 +266,84 @@ func (m *instance) collectEventData(ctx context.Context) (eventTriggers, cluster return eventTriggers, clusterHealthChecks, nil } +func (m *instance) collectManagementClusterInfo(ctx context.Context) (provider, k8sVersion string, nodeCount int) { + logger := log.FromContext(ctx) + + discoveryClient, err := discovery.NewDiscoveryClientForConfig(m.config) + if err != nil { + logger.V(logs.LogInfo).Info(fmt.Sprintf("failed to create discovery client: %v", err)) + } else { + serverVersion, err := discoveryClient.ServerVersion() + if err != nil { + logger.V(logs.LogInfo).Info(fmt.Sprintf("failed to get server version: %v", err)) + } else { + k8sVersion = serverVersion.GitVersion + } + } + + var nodes corev1.NodeList + if err := m.List(ctx, &nodes); err != nil { + logger.V(logs.LogInfo).Info(fmt.Sprintf("failed to list nodes: %v", err)) + return + } + nodeCount = len(nodes.Items) + provider = detectClusterProvider(nodes.Items) + return +} + +func detectClusterProvider(nodes []corev1.Node) string { + for i := range nodes { + node := &nodes[i] + labels := node.Labels + + if _, ok := labels["eks.amazonaws.com/nodegroup"]; ok { + return providerEKS + } + if _, ok := labels["cloud.google.com/gke-nodepool"]; ok { + return providerGKE + } + if _, ok := labels["kubernetes.azure.com/agentpool"]; ok { + return providerAKS + } + if _, ok := labels["node.openshift.io/os_id"]; ok { + return "openshift" + } + + providerID := node.Spec.ProviderID + switch { + case strings.HasPrefix(providerID, "aws://"): + return providerEKS + case strings.HasPrefix(providerID, "gce://"): + return providerGKE + case strings.HasPrefix(providerID, "azure://"): + return providerAKS + case strings.HasPrefix(providerID, "vsphere://"): + return "vsphere" + } + + kubeletVersion := node.Status.NodeInfo.KubeletVersion + switch { + case strings.Contains(kubeletVersion, "+k3s"): + return "k3s" + case strings.Contains(kubeletVersion, "k0s"): + return "k0s" + case strings.Contains(kubeletVersion, "+rke2"): + return "rke2" + case strings.Contains(kubeletVersion, "+rke"): + return "rke" + case strings.Contains(kubeletVersion, "-eks-"): + return "eks" + case strings.Contains(kubeletVersion, "-gke."): + return "gke" + } + + if hostname := labels["kubernetes.io/hostname"]; strings.HasPrefix(hostname, "kind-") { + return "kind" + } + } + return "unknown" +} + func (m *instance) sendData(ctx context.Context, payload *libsveltostelemetry.Cluster) { logger := log.FromContext(ctx) diff --git a/test/pullmode-sveltosapplier.yaml b/test/pullmode-sveltosapplier.yaml index 03cc7ba4..462d4a0c 100644 --- a/test/pullmode-sveltosapplier.yaml +++ b/test/pullmode-sveltosapplier.yaml @@ -99,7 +99,7 @@ spec: valueFrom: fieldRef: fieldPath: metadata.namespace - image: docker.io/projectsveltos/sveltos-applier@sha256:1d2e0f7921212f93fa3cd2607c57eefb305b3d06e1a71a27a5fd1919fd1b6566 + image: docker.io/projectsveltos/sveltos-applier@sha256:8262f5598d29079afe5d71c221d9db2e89a752b9798fa16ab03a3496abc631c2 livenessProbe: failureThreshold: 3 httpGet: