diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 70145e6f9..c14af1467 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -16,6 +16,7 @@ updates: - /instrumentor - /odiglet - /opampserver + - /instrumentation schedule: day: monday interval: weekly diff --git a/.github/workflows/publish-modules.yml b/.github/workflows/publish-modules.yml index 5333dfd3b..e904785e8 100644 --- a/.github/workflows/publish-modules.yml +++ b/.github/workflows/publish-modules.yml @@ -62,6 +62,10 @@ jobs: run: | git tag opampserver/${{ steps.extract_tag.outputs.tag }} + - name: tag instrumentation + run: | + git tag instrumentation/${{ steps.extract_tag.outputs.tag }} + - name: Push Module Tags run: | git push origin --tags diff --git a/autoscaler/controllers/datacollection/daemonset.go b/autoscaler/controllers/datacollection/daemonset.go index 7049263d8..a8063bdaa 100644 --- a/autoscaler/controllers/datacollection/daemonset.go +++ b/autoscaler/controllers/datacollection/daemonset.go @@ -192,8 +192,10 @@ func getDesiredDaemonSet(datacollection *odigosv1.CollectorsGroup, rollingUpdate.MaxSurge = &maxSurge } - requestMemoryRequestQuantity := resource.MustParse(fmt.Sprintf("%dMi", datacollection.Spec.ResourcesSettings.MemoryRequestMiB)) - requestMemoryLimitQuantity := resource.MustParse(fmt.Sprintf("%dMi", datacollection.Spec.ResourcesSettings.MemoryLimitMiB)) + resourceMemoryRequestQuantity := resource.MustParse(fmt.Sprintf("%dMi", datacollection.Spec.ResourcesSettings.MemoryRequestMiB)) + resourceMemoryLimitQuantity := resource.MustParse(fmt.Sprintf("%dMi", datacollection.Spec.ResourcesSettings.MemoryLimitMiB)) + resourceCpuRequestQuantity := resource.MustParse(fmt.Sprintf("%dm", datacollection.Spec.ResourcesSettings.CpuRequestMillicores)) + resourceCpuLimitQuantity := resource.MustParse(fmt.Sprintf("%dm", datacollection.Spec.ResourcesSettings.CpuLimitMillicores)) desiredDs := &appsv1.DaemonSet{ ObjectMeta: metav1.ObjectMeta{ @@ -326,10 +328,12 @@ func getDesiredDaemonSet(datacollection *odigosv1.CollectorsGroup, }, Resources: corev1.ResourceRequirements{ Requests: corev1.ResourceList{ - corev1.ResourceMemory: requestMemoryRequestQuantity, + corev1.ResourceMemory: resourceMemoryRequestQuantity, + corev1.ResourceCPU: resourceCpuRequestQuantity, }, Limits: corev1.ResourceList{ - corev1.ResourceMemory: requestMemoryLimitQuantity, + corev1.ResourceMemory: resourceMemoryLimitQuantity, + corev1.ResourceCPU: resourceCpuLimitQuantity, }, }, SecurityContext: &corev1.SecurityContext{ diff --git a/autoscaler/controllers/gateway/deployment.go b/autoscaler/controllers/gateway/deployment.go index 002ec1b5c..a89a66fd1 100644 --- a/autoscaler/controllers/gateway/deployment.go +++ b/autoscaler/controllers/gateway/deployment.go @@ -171,6 +171,19 @@ func getDesiredDeployment(dests *odigosv1.DestinationList, configDataHash string Name: "GOMEMLIMIT", Value: fmt.Sprintf("%dMiB", gateway.Spec.ResourcesSettings.GomemlimitMiB), }, + { + // let the Go runtime know how many CPUs are available, + // without this, Go will assume all the cores are available. + Name: "GOMAXPROCS", + ValueFrom: &corev1.EnvVarSource{ + ResourceFieldRef: &corev1.ResourceFieldSelector{ + ContainerName: containerName, + // limitCPU, Kubernetes automatically rounds up the value to an integer + // (700m -> 1, 1200m -> 2) + Resource: "limits.cpu", + }, + }, + }, }, SecurityContext: &corev1.SecurityContext{ AllowPrivilegeEscalation: boolPtr(false), diff --git a/cli/cmd/resources/odigosconfig.go b/cli/cmd/resources/odigosconfig.go index 6d66c4df0..ba7fe99e6 100644 --- a/cli/cmd/resources/odigosconfig.go +++ b/cli/cmd/resources/odigosconfig.go @@ -49,10 +49,15 @@ func (a *odigosConfigResourceManager) Name() string { return "OdigosConfig" } func (a *odigosConfigResourceManager) InstallFromScratch(ctx context.Context) error { sizingProfile := k8sprofiles.FilterSizeProfiles(a.config.Profiles) + collectorGatewayConfig := GetGatewayConfigBasedOnSize(sizingProfile) - collectorNodeConfig := GetNodeCollectorConfigBasedOnSize(sizingProfile) a.config.CollectorGateway = collectorGatewayConfig - if a.config.CollectorNode != nil { + + collectorNodeConfig := GetNodeCollectorConfigBasedOnSize(sizingProfile) + if a.config.CollectorNode != nil && a.config.CollectorNode.CollectorOwnMetricsPort != 0 { + if collectorNodeConfig == nil { + collectorNodeConfig = &common.CollectorNodeConfiguration{} + } collectorNodeConfig.CollectorOwnMetricsPort = a.config.CollectorNode.CollectorOwnMetricsPort } a.config.CollectorNode = collectorNodeConfig @@ -77,16 +82,22 @@ func GetNodeCollectorConfigBasedOnSize(profile common.ProfileName) *common.Colle return &common.CollectorNodeConfiguration{ RequestMemoryMiB: 150, LimitMemoryMiB: 300, + RequestCPUm: 150, + LimitCPUm: 300, } case k8sprofiles.SizeMProfile.ProfileName: return &common.CollectorNodeConfiguration{ RequestMemoryMiB: 250, LimitMemoryMiB: 500, + RequestCPUm: 250, + LimitCPUm: 500, } case k8sprofiles.SizeLProfile.ProfileName: return &common.CollectorNodeConfiguration{ RequestMemoryMiB: 500, LimitMemoryMiB: 750, + RequestCPUm: 500, + LimitCPUm: 750, } } } diff --git a/cli/cmd/ui.go b/cli/cmd/ui.go index 963aea9cc..dad316a83 100644 --- a/cli/cmd/ui.go +++ b/cli/cmd/ui.go @@ -26,8 +26,8 @@ import ( ) const ( - defaultPort = 3000 - betaDefaultPort = 3001 + defaultPort = 3000 + legacyDefaultPort = 3001 ) // uiCmd represents the ui command @@ -50,12 +50,12 @@ var uiCmd = &cobra.Command{ } } - betaFlag, _ := cmd.Flags().GetBool("beta") + legacyFlag, _ := cmd.Flags().GetBool("legacy") localPort := cmd.Flag("port").Value.String() clusterPort := defaultPort - if betaFlag { - clusterPort = betaDefaultPort + if legacyFlag { + clusterPort = legacyDefaultPort } localAddress := cmd.Flag("address").Value.String() diff --git a/common/go.mod b/common/go.mod index 5f8b39c00..5a56cf5dc 100644 --- a/common/go.mod +++ b/common/go.mod @@ -10,7 +10,7 @@ require ( require ( github.com/kr/pretty v0.3.1 // indirect - github.com/rogpeppe/go-internal v1.10.0 // indirect + github.com/rogpeppe/go-internal v1.11.0 // indirect golang.org/x/crypto v0.21.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect ) @@ -24,7 +24,7 @@ require ( github.com/mattn/go-isatty v0.0.12 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/otel v1.29.0 - golang.org/x/sys v0.18.0 // indirect + golang.org/x/sys v0.20.0 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/common/go.sum b/common/go.sum index 0119df611..a3e62e022 100644 --- a/common/go.sum +++ b/common/go.sum @@ -34,8 +34,8 @@ github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsK github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= -github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw= @@ -46,8 +46,8 @@ golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/common/odigos_config.go b/common/odigos_config.go index bb82cdf91..33a028875 100644 --- a/common/odigos_config.go +++ b/common/odigos_config.go @@ -17,6 +17,16 @@ type CollectorNodeConfiguration struct { // default value is 2x the memory request. LimitMemoryMiB int `json:"limitMemoryMiB,omitempty"` + // RequestCPUm is the CPU request for the node collector daemonset. + // it will be embedded in the daemonset as a resource request of the form "cpu: m" + // default value is 250m + RequestCPUm int `json:"requestCPUm,omitempty"` + + // LimitCPUm is the CPU limit for the node collector daemonset. + // it will be embedded in the daemonset as a resource limit of the form "cpu: m" + // default value is 500m + LimitCPUm int `json:"limitCPUm,omitempty"` + // this parameter sets the "limit_mib" parameter in the memory limiter configuration for the node collector. // it is the hard limit after which a force garbage collection will be performed. // if not set, it will be 50Mi below the memory request. diff --git a/destinations/go.mod b/destinations/go.mod index 813187e17..1a0569699 100644 --- a/destinations/go.mod +++ b/destinations/go.mod @@ -3,7 +3,7 @@ module github.com/odigos-io/odigos/destinations go 1.23.0 require ( - github.com/odigos-io/odigos/common v1.0.48 + github.com/odigos-io/odigos/common v0.0.0 gopkg.in/yaml.v3 v3.0.1 ) diff --git a/destinations/go.sum b/destinations/go.sum index e2ad6d10a..d7de70577 100644 --- a/destinations/go.sum +++ b/destinations/go.sum @@ -13,8 +13,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= -github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw= diff --git a/docs/pipeline/configuration.mdx b/docs/pipeline/configuration.mdx index 9053f232f..fac334997 100644 --- a/docs/pipeline/configuration.mdx +++ b/docs/pipeline/configuration.mdx @@ -36,11 +36,11 @@ Sizing Profiles `size_s`, `size_m`, `size_l` are pre-defined configurations desi **Node Data Collection Collector**: -| Profile | Request Memory (Mi) | Limit Memory (Mi) | -|----------|----------------------|-------------------| -| `size_s` | **150Mi** | **300Mi** | -| `size_m` | **250Mi** | **500Mi** | -| `size_l` | **500Mi** | **750Mi** | +| Profile | Request Memory (Mi) | Limit Memory (Mi) | Request CPU (m) | Limit CPU (m) +|----------|----------------------|-------------------| ---------------------|-------------------| +| `size_s` | **150Mi** | **300Mi** | **150m** | **300m** | +| `size_m` | **250Mi** | **500Mi** | **250m** | **500m** | +| `size_l` | **500Mi** | **750Mi** | **500m** | **750m** | To use profiles, you need to use the [Odigos CLI Command for Profiles](/cli/odigos_profile). @@ -96,27 +96,37 @@ collectorNode: # RequestMemoryMiB is the memory request for the node collector daemonset. # it will be embedded in the daemonset as a resource request of the form "memory: Mi" # default value is 250Mi - RequestMemoryMiB int `json:"requestMemoryMiB,omitempty"` + requestMemoryMiB: 250 # LimitMemoryMiB is the memory limit for the node collector daemonset. # it will be embedded in the daemonset as a resource limit of the form "memory: Mi" # default value is 2x the memory request. - LimitMemoryMiB int `json:"limitMemoryMiB,omitempty"` + limitMemoryMiB: 500 + + # RequestCPUm is the CPU request for the node collector daemonset. + # it will be embedded in the daemonset as a resource request of the form "cpu: m" + # default value is 250m + requestCPUm: 250 + + # LimitCPUm is the CPU limit for the node collector daemonset. + # it will be embedded in the daemonset as a resource limit of the form "cpu: m" + # default value is 500m + limitCPUm: 500 # this parameter sets the "limit_mib" parameter in the memory limiter configuration for the node collector. # it is the hard limit after which a force garbage collection will be performed. # if not set, it will be 50Mi below the memory request. - MemoryLimiterLimitMiB int `json:"memoryLimiterLimitMiB,omitempty"` + memoryLimiterLimitMiB: # this parameter sets the "spike_limit_mib" parameter in the memory limiter configuration for the node collector. # note that this is not the processor soft limit, but the diff in Mib between the hard limit and the soft limit. # if not set, this will be set to 20% of the hard limit (so the soft limit will be 80% of the hard limit). - MemoryLimiterSpikeLimitMiB int `json:"memoryLimiterSpikeLimitMiB,omitempty"` + memoryLimiterSpikeLimitMiB: # the GOMEMLIMIT environment variable value for the node collector daemonset. # this is when go runtime will start garbage collection. # if not specified, it will be set to 80% of the hard limit of the memory limiter. - GoMemLimitMib int `json:"goMemLimitMiB,omitempty"` + goMemLimitMiB: ``` diff --git a/docs/quickstart/installation.mdx b/docs/quickstart/installation.mdx index c9ae69973..70b347d8a 100644 --- a/docs/quickstart/installation.mdx +++ b/docs/quickstart/installation.mdx @@ -76,14 +76,13 @@ odigos ui By default, Odigos UI is available at http://localhost:3000. -## Experimental: New UI with --beta flag +## Using the Legacy UI ```bash -odigos ui --beta +odigos ui --legacy ``` - The --beta flag provides access to a new, improved UI. Keep in mind that this - is an experimental feature and may include changes or incomplete - functionality. + The new UI is the default experience. The legacy UI remains available for + users who prefer the previous version. diff --git a/frontend/main.go b/frontend/main.go index 1431fb740..74346aed8 100644 --- a/frontend/main.go +++ b/frontend/main.go @@ -42,14 +42,14 @@ import ( const ( defaultPort = 3000 - betaPort = 3001 + legacyPort = 3001 ) type Flags struct { Version bool Address string Port int - BetaPort int + LegacyPort int Debug bool KubeConfig string Namespace string @@ -68,7 +68,7 @@ func parseFlags() Flags { flag.BoolVar(&flags.Version, "version", false, "Print Odigos UI version.") flag.StringVar(&flags.Address, "address", "localhost", "Address to listen on") flag.IntVar(&flags.Port, "port", defaultPort, "Port to listen on") - flag.IntVar(&flags.BetaPort, "beta-port", betaPort, "Port to listen on for beta UI") + flag.IntVar(&flags.LegacyPort, "legacy-port", legacyPort, "Port to listen on for legacy UI") flag.BoolVar(&flags.Debug, "debug", false, "Enable debug mode") flag.StringVar(&flags.KubeConfig, "kubeconfig", defaultKubeConfig, "Path to kubeconfig file") flag.StringVar(&flags.Namespace, "namespace", consts.DefaultOdigosNamespace, "Kubernetes namespace where Odigos is installed") @@ -334,20 +334,18 @@ func main() { r.GET("/api/events", sse.HandleSSEConnections) d.GET("/api/events", sse.HandleSSEConnections) - log.Println("Starting Odigos UI...") - log.Printf("Odigos UI is available at: http://%s:%d", flags.Address, flags.BetaPort) + log.Printf("Odigos UI is available at: http://%s:%d", flags.Address, flags.Port) go func() { - err = r.Run(fmt.Sprintf("%s:%d", flags.Address, flags.BetaPort)) + err = r.Run(fmt.Sprintf("%s:%d", flags.Address, flags.Port)) if err != nil { log.Fatalf("Error starting server: %s", err) } }() go func() { - log.Println("Starting Odigos Dep UI...") - log.Printf("Odigos UI is available at: http://%s:%d", flags.Address, flags.Port) - err = d.Run(fmt.Sprintf("%s:%d", flags.Address, flags.Port)) + log.Printf("Odigos Legacy UI is available at: http://%s:%d", flags.Address, flags.LegacyPort) + err = d.Run(fmt.Sprintf("%s:%d", flags.Address, flags.LegacyPort)) if err != nil { log.Fatalf("Error starting server: %s", err) } diff --git a/frontend/webapp/reuseable-components/data-card/data-card-fields/index.tsx b/frontend/webapp/reuseable-components/data-card/data-card-fields/index.tsx index 7527d9928..cfdfb8ceb 100644 --- a/frontend/webapp/reuseable-components/data-card/data-card-fields/index.tsx +++ b/frontend/webapp/reuseable-components/data-card/data-card-fields/index.tsx @@ -111,9 +111,8 @@ const renderValue = (type: DataCardRow['type'], value: DataCardRow['value']) => } /> )} - > - - + renderActions={() => } + /> ); } diff --git a/frontend/webapp/reuseable-components/data-tab/index.tsx b/frontend/webapp/reuseable-components/data-tab/index.tsx index b9d79a6b7..1fa6cbf4b 100644 --- a/frontend/webapp/reuseable-components/data-tab/index.tsx +++ b/frontend/webapp/reuseable-components/data-tab/index.tsx @@ -1,10 +1,10 @@ -import React, { Fragment, PropsWithChildren, useCallback, useState } from 'react'; +import React, { Fragment, useCallback, useState } from 'react'; import Image from 'next/image'; import { FlexColumn, FlexRow } from '@/styles'; import styled, { css } from 'styled-components'; import { ActiveStatus, Divider, ExtendIcon, IconButton, MonitorsIcons, Text } from '@/reuseable-components'; -interface Props extends PropsWithChildren { +interface Props { title: string; subTitle: string; logo: string; diff --git a/frontend/webapp/reuseable-components/nodes-data-flow/nodes/base-node.tsx b/frontend/webapp/reuseable-components/nodes-data-flow/nodes/base-node.tsx index 583103e5b..e7ea1a084 100644 --- a/frontend/webapp/reuseable-components/nodes-data-flow/nodes/base-node.tsx +++ b/frontend/webapp/reuseable-components/nodes-data-flow/nodes/base-node.tsx @@ -74,10 +74,7 @@ const BaseNode: React.FC = ({ id: nodeId, data }) => { return ( - {}}> - {renderActions()} - - + {}} renderActions={renderActions} /> diff --git a/helm/odigos/templates/odigos-config-cm.yaml b/helm/odigos/templates/odigos-config-cm.yaml index 0ec3577fd..84d7d608e 100644 --- a/helm/odigos/templates/odigos-config-cm.yaml +++ b/helm/odigos/templates/odigos-config-cm.yaml @@ -56,6 +56,12 @@ data: {{- with .Values.collectorNode.limitMemoryMiB }} limitMemoryMiB: {{ . }} {{- end }} + {{- with .Values.collectorNode.requestCPUm }} + requestCPUm: {{ . }} + {{- end }} + {{- with .Values.collectorNode.limitCPUm }} + limitCPUm: {{ . }} + {{- end }} {{- with .Values.collectorNode.memoryLimiterLimitMiB }} memoryLimiterLimitMiB: {{ . }} {{- end }} diff --git a/helm/odigos/values.yaml b/helm/odigos/values.yaml index fbcd4501e..8955e7f94 100644 --- a/helm/odigos/values.yaml +++ b/helm/odigos/values.yaml @@ -77,6 +77,17 @@ collectorNode: # default value is 2x the memory request. limitMemoryMiB: 500 + # the CPU request for the node collector daemonset. + # it will be embedded in the daemonset as a resource request + # of the form "cpu: m". + # default value is 250m + requestCPUm: 250 + # the CPU limit for the node collector daemonset. + # it will be embedded in the daemonset as a resource limit + # of the form "cpu: m". + # default value is 500m + limitCPUm: 500 + # this parameter sets the "limit_mib" parameter in the memory limiter configuration for the node collector. # it is the hard limit after which a force garbage collection will be performed. # if not set, it will be 50Mi below the memory limit. diff --git a/instrumentation/detector/detector.go b/instrumentation/detector/detector.go new file mode 100644 index 000000000..9d8060544 --- /dev/null +++ b/instrumentation/detector/detector.go @@ -0,0 +1,29 @@ +package detector + +import ( + "context" + + detector "github.com/odigos-io/runtime-detector" +) + +type ProcessEvent = detector.ProcessEvent + +type DetectorOption = detector.DetectorOption + +const ( + ProcessExecEvent = detector.ProcessExecEvent + ProcessExitEvent = detector.ProcessExitEvent +) + +// Detector is used to report process events. +type Detector interface { + Run(ctx context.Context) error +} + +// NewDetector creates a new Detector. +// +// The process events are sent to the events channel. +// The channel is closed when the detector is stopped (just before returning from Run). +func NewDetector(events chan<- ProcessEvent, opts ...DetectorOption) (Detector, error) { + return detector.NewDetector(events, opts...) +} diff --git a/odiglet/pkg/ebpf/factory.go b/instrumentation/factory.go similarity index 72% rename from odiglet/pkg/ebpf/factory.go rename to instrumentation/factory.go index 4d0098b60..9c0706faa 100644 --- a/odiglet/pkg/ebpf/factory.go +++ b/instrumentation/factory.go @@ -1,14 +1,13 @@ -package ebpf +package instrumentation import ( "context" - odigosv1 "github.com/odigos-io/odigos/api/odigos/v1alpha1" - "github.com/odigos-io/odigos/common" - "go.opentelemetry.io/otel/attribute" ) +type Config any + // Settings is used to pass initial configuration to the instrumentation type Settings struct { // ServiceName is the name of the service that is being instrumented @@ -19,7 +18,7 @@ type Settings struct { ResourceAttributes []attribute.KeyValue // InitialConfig is the initial configuration that should be applied to the instrumentation, // it can be used to enable/disable specific instrumentation libraries, configure sampling, etc. - InitialConfig *odigosv1.SdkConfig + InitialConfig Config } // Factory is used to create an Instrumentation @@ -29,15 +28,6 @@ type Factory interface { CreateInstrumentation(ctx context.Context, pid int, settings Settings) (Instrumentation, error) } -// OtelDistribution is a customized version of an OpenTelemetry component. -// see https://opentelemetry.io/docs/concepts/distributions and https://github.com/odigos-io/odigos/pull/1776#discussion_r1853367917 for more information. -// TODO: This should be moved to a common package, since it will require a bigger refactor across multiple components, -// we use this local definition for now. -type OtelDistribution struct { - Language common.ProgrammingLanguage - OtelSdk common.OtelSdk -} - // Instrumentation is used to instrument a running process type Instrumentation interface { // Loads the relevant probes, and will perform any initialization required @@ -46,7 +36,7 @@ type Instrumentation interface { // In case of a failure, an error will be returned and all the resources will be cleaned up. Load(ctx context.Context) error - // Run will attach the probes to the relevant process, and will start the instrumentation. + // Run will start reading events from the probes and export them. // It is a blocking call, and will return only when the instrumentation is stopped. // During the run, telemetry will be collected from the probes and sent with the configured exporter. // Run will return when either a fatal error occurs, the context is canceled, or Close is called. @@ -57,5 +47,5 @@ type Instrumentation interface { Close(ctx context.Context) error // ApplyConfig will send a configuration update to the instrumentation. - ApplyConfig(ctx context.Context, config *odigosv1.SdkConfig) error + ApplyConfig(ctx context.Context, config Config) error } diff --git a/instrumentation/go.mod b/instrumentation/go.mod new file mode 100644 index 000000000..9c085327f --- /dev/null +++ b/instrumentation/go.mod @@ -0,0 +1,21 @@ +module github.com/odigos-io/odigos/instrumentation + +go 1.23.0 + +require ( + github.com/go-logr/logr v1.4.2 + github.com/odigos-io/odigos/common v0.0.0 + github.com/odigos-io/runtime-detector v0.0.4 + go.opentelemetry.io/otel v1.33.0 + golang.org/x/sync v0.10.0 +) + +require ( + github.com/cilium/ebpf v0.16.0 // indirect + github.com/hashicorp/go-version v1.7.0 // indirect + go.opentelemetry.io/otel/trace v1.33.0 // indirect + golang.org/x/exp v0.0.0-20230224173230-c95f2b4c22f2 // indirect + golang.org/x/sys v0.20.0 // indirect +) + +replace github.com/odigos-io/odigos/common => ../common diff --git a/instrumentation/go.sum b/instrumentation/go.sum new file mode 100644 index 000000000..e0cf9882a --- /dev/null +++ b/instrumentation/go.sum @@ -0,0 +1,46 @@ +github.com/cilium/ebpf v0.16.0 h1:+BiEnHL6Z7lXnlGUsXQPPAE7+kenAd4ES8MQ5min0Ok= +github.com/cilium/ebpf v0.16.0/go.mod h1:L7u2Blt2jMM/vLAVgjxluxtBKlz3/GWjB0dMOEngfwE= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI= +github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= +github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA= +github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= +github.com/jsimonetti/rtnetlink/v2 v2.0.1 h1:xda7qaHDSVOsADNouv7ukSuicKZO7GgVUCXxpaIEIlM= +github.com/jsimonetti/rtnetlink/v2 v2.0.1/go.mod h1:7MoNYNbb3UaDHtF8udiJo/RH6VsTKP1pqKLUTVCvToE= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g= +github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw= +github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U= +github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA= +github.com/odigos-io/runtime-detector v0.0.4 h1:q4yap5yTApkFFSRdwnU6NZeV+IbzEzWJZv6IEVCVKyE= +github.com/odigos-io/runtime-detector v0.0.4/go.mod h1:m8GfdG6pET0K/8aoZwnX+MkYz8oVroKs8HzRnkuJWt4= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +go.opentelemetry.io/otel v1.33.0 h1:/FerN9bax5LoK51X/sI0SVYrjSE0/yUL7DpxW4K3FWw= +go.opentelemetry.io/otel v1.33.0/go.mod h1:SUUkR6csvUQl+yjReHu5uM3EtVV7MBm5FHKRlNx4I8I= +go.opentelemetry.io/otel/trace v1.33.0 h1:cCJuF7LRjUFso9LPnEAHJDB2pqzp+hbO8eu1qqW2d/s= +go.opentelemetry.io/otel/trace v1.33.0/go.mod h1:uIcdVUZMpTAmz0tI1z04GoVSezK37CbGV4fr1f2nBck= +golang.org/x/exp v0.0.0-20230224173230-c95f2b4c22f2 h1:Jvc7gsqn21cJHCmAWx0LiimpP18LZmUxkT5Mp7EZ1mI= +golang.org/x/exp v0.0.0-20230224173230-c95f2b4c22f2/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= +golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= +golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/instrumentation/manager.go b/instrumentation/manager.go new file mode 100644 index 000000000..94f037603 --- /dev/null +++ b/instrumentation/manager.go @@ -0,0 +1,345 @@ +package instrumentation + +import ( + "context" + "errors" + "fmt" + + "golang.org/x/sync/errgroup" + + "github.com/go-logr/logr" + + "github.com/odigos-io/odigos/instrumentation/detector" +) + +var ( + errNoInstrumentationFactory = errors.New("no ebpf factory found") + errFailedToGetDetails = errors.New("failed to get details for process event") + errFailedToGetDistribution = errors.New("failed to get otel distribution for details") + errFailedToGetConfigGroup = errors.New("failed to get config group") +) + +// ConfigUpdate is used to send a configuration update request to the manager. +// The manager will apply the configuration to all instrumentations that match the config group. +type ConfigUpdate[configGroup ConfigGroup] map[configGroup]Config + +type instrumentationDetails[processGroup ProcessGroup, configGroup ConfigGroup] struct { + inst Instrumentation + pg processGroup + cg configGroup +} + +type ManagerOptions[processGroup ProcessGroup, configGroup ConfigGroup] struct { + Logger logr.Logger + + // Factories is a map of OTel distributions to their corresponding instrumentation factories. + // + // The manager will use this map to create new instrumentations based on the process event. + // If a process event is received and the OTel distribution is not found in this map, + // the manager will ignore the event. + Factories map[OtelDistribution]Factory + + // Handler is used to resolve details, config group, OTel distribution and settings for the instrumentation + // based on the process event. + // + // The handler is also used to report the instrumentation lifecycle events. + Handler *Handler[processGroup, configGroup] + + // DetectorOptions is a list of options to configure the process detector. + // + // The process detector is used to trigger new instrumentation for new relevant processes, + // and un-instrumenting processes once they exit. + DetectorOptions []detector.DetectorOption + + // ConfigUpdates is a channel for receiving configuration updates. + // The manager will apply the configuration to all instrumentations that match the config group. + // + // The caller is responsible for closing the channel once no more updates are expected. + ConfigUpdates <-chan ConfigUpdate[configGroup] +} + +// Manager is used to orchestrate the ebpf instrumentations lifecycle. +type Manager interface { + // Run launches the manger. + // It will block until the context is canceled. + // It is an error to not cancel the context before the program exits, and may result in leaked resources. + Run(ctx context.Context) error +} + +type manager[processGroup ProcessGroup, configGroup ConfigGroup] struct { + // channel for receiving process events, + // used to detect new processes and process exits, and handle their instrumentation accordingly. + procEvents <-chan detector.ProcessEvent + detector detector.Detector + handler *Handler[processGroup, configGroup] + factories map[OtelDistribution]Factory + logger logr.Logger + + // all the active instrumentations by pid, + // this map is not concurrent safe, so it should be accessed only from the main event loop + detailsByPid map[int]*instrumentationDetails[processGroup, configGroup] + + // active instrumentations by workload, and aggregated by pid + // this map is not concurrent safe, so it should be accessed only from the main event loop + detailsByWorkload map[configGroup]map[int]*instrumentationDetails[processGroup, configGroup] + + configUpdates <-chan ConfigUpdate[configGroup] +} + +func NewManager[processGroup ProcessGroup, configGroup ConfigGroup](options ManagerOptions[processGroup, configGroup]) (Manager, error) { + handler := options.Handler + if handler == nil { + return nil, errors.New("handler is required for ebpf instrumentation manager") + } + + if handler.Reporter == nil { + return nil, errors.New("reporter is required for ebpf instrumentation manager") + } + + if handler.ProcessGroupResolver == nil { + return nil, errors.New("details resolver is required for ebpf instrumentation manager") + } + + if handler.ConfigGroupResolver == nil { + return nil, errors.New("config group resolver is required for ebpf instrumentation manager") + } + + if handler.DistributionMatcher == nil { + return nil, errors.New("distribution matcher is required for ebpf instrumentation manager") + } + + if handler.SettingsGetter == nil { + return nil, errors.New("settings getter is required for ebpf instrumentation manager") + } + + if options.ConfigUpdates == nil { + return nil, errors.New("config updates channel is required for ebpf instrumentation manager") + } + + logger := options.Logger + procEvents := make(chan detector.ProcessEvent) + detector, err := detector.NewDetector(procEvents, options.DetectorOptions...) + if err != nil { + return nil, fmt.Errorf("failed to create process detector: %w", err) + } + + return &manager[processGroup, configGroup]{ + procEvents: procEvents, + detector: detector, + handler: handler, + factories: options.Factories, + logger: logger.WithName("ebpf-instrumentation-manager"), + detailsByPid: make(map[int]*instrumentationDetails[processGroup, configGroup]), + detailsByWorkload: map[configGroup]map[int]*instrumentationDetails[processGroup, configGroup]{}, + configUpdates: options.ConfigUpdates, + }, nil +} + +func (m *manager[ProcessGroup, ConfigGroup]) runEventLoop(ctx context.Context) { + // main event loop for handling instrumentations + for { + select { + case <-ctx.Done(): + m.logger.Info("stopping eBPF instrumentation manager") + for pid, details := range m.detailsByPid { + err := details.inst.Close(ctx) + if err != nil { + m.logger.Error(err, "failed to close instrumentation", "pid", pid) + } + // probably shouldn't remove instrumentation instance here + // as this flow is happening when Odiglet is shutting down + } + m.detailsByPid = nil + m.detailsByWorkload = nil + return + case e := <-m.procEvents: + switch e.EventType { + case detector.ProcessExecEvent: + m.logger.V(1).Info("detected new process", "pid", e.PID, "cmd", e.ExecDetails.CmdLine) + err := m.handleProcessExecEvent(ctx, e) + // ignore the error if no instrumentation factory is found, + // as this is expected for some language and sdk combinations + if err != nil && !errors.Is(err, errNoInstrumentationFactory) { + m.logger.Error(err, "failed to handle process exec event") + } + case detector.ProcessExitEvent: + m.cleanInstrumentation(ctx, e.PID) + } + case configUpdate := <-m.configUpdates: + for configGroup, config := range configUpdate { + err := m.applyInstrumentationConfigurationForSDK(ctx, configGroup, config) + if err != nil { + m.logger.Error(err, "failed to apply instrumentation configuration") + } + } + } + } +} + +func (m *manager[ProcessGroup, ConfigGroup]) Run(ctx context.Context) error { + g, errCtx := errgroup.WithContext(ctx) + + g.Go(func() error { + return m.detector.Run(errCtx) + }) + + g.Go(func() error { + m.runEventLoop(errCtx) + return nil + }) + + err := g.Wait() + return err +} + +func (m *manager[ProcessGroup, ConfigGroup]) cleanInstrumentation(ctx context.Context, pid int) { + details, found := m.detailsByPid[pid] + if !found { + m.logger.V(3).Info("no instrumentation found for exiting pid, nothing to clean", "pid", pid) + return + } + + m.logger.Info("cleaning instrumentation resources", "pid", pid, "process group details", details.pg) + + err := details.inst.Close(ctx) + if err != nil { + m.logger.Error(err, "failed to close instrumentation") + } + + err = m.handler.Reporter.OnExit(ctx, pid, details.pg) + if err != nil { + m.logger.Error(err, "failed to report instrumentation exit") + } + + m.stopTrackInstrumentation(pid) +} + +func (m *manager[ProcessGroup, ConfigGroup]) handleProcessExecEvent(ctx context.Context, e detector.ProcessEvent) error { + if _, found := m.detailsByPid[e.PID]; found { + // this can happen if we have multiple exec events for the same pid (chain loading) + // TODO: better handle this? + // this can be done by first closing the existing instrumentation, + // and then creating a new one + m.logger.Info("received exec event for process id which is already instrumented with ebpf, skipping it", "pid", e.PID) + return nil + } + + pg, err := m.handler.ProcessGroupResolver.Resolve(ctx, e) + if err != nil { + return errors.Join(err, errFailedToGetDetails) + } + + otelDisto, err := m.handler.DistributionMatcher.Distribution(ctx, pg) + if err != nil { + return errors.Join(err, errFailedToGetDistribution) + } + + configGroup, err := m.handler.ConfigGroupResolver.Resolve(ctx, pg, otelDisto) + if err != nil { + return errors.Join(err, errFailedToGetConfigGroup) + } + + factory, found := m.factories[otelDisto] + if !found { + return errNoInstrumentationFactory + } + + // Fetch initial settings for the instrumentation + settings, err := m.handler.SettingsGetter.Settings(ctx, pg, otelDisto) + if err != nil { + // for k8s instrumentation config CR will be queried to get the settings + // we should always have config for this event. + // if missing, it means that either: + // - the config will be generated later due to reconciliation timing in instrumentor + // - just got deleted and the pod (and the process) will go down soon + // TODO: sync reconcilers so inst config is guaranteed be created before the webhook is enabled + // + m.logger.Info("failed to get initial settings for instrumentation", "language", otelDisto.Language, "sdk", otelDisto.OtelSdk, "error", err) + // return nil + } + + inst, err := factory.CreateInstrumentation(ctx, e.PID, settings) + if err != nil { + m.logger.Error(err, "failed to initialize instrumentation", "language", otelDisto.Language, "sdk", otelDisto.OtelSdk) + err = m.handler.Reporter.OnInit(ctx, e.PID, err, pg) + // TODO: should we return here the initialize error? or the handler error? or both? + return err + } + + err = inst.Load(ctx) + // call the reporter regardless of the load result - as we want to report the load status + reporterErr := m.handler.Reporter.OnLoad(ctx, e.PID, err, pg) + if err != nil { + m.logger.Error(err, "failed to load instrumentation", "language", otelDisto.Language, "sdk", otelDisto.OtelSdk) + // TODO: should we return here the load error? or the instance write error? or both? + return err + } + + if reporterErr != nil { + m.logger.Error(reporterErr, "failed to report instrumentation load") + } + + m.startTrackInstrumentation(e.PID, inst, pg, configGroup) + + m.logger.Info("instrumentation loaded", "pid", e.PID, "process group details", pg) + + go func() { + err := inst.Run(ctx) + if err != nil && !errors.Is(err, context.Canceled) { + reporterErr := m.handler.Reporter.OnRun(ctx, e.PID, err, pg) + if reporterErr != nil { + m.logger.Error(reporterErr, "failed to report instrumentation run") + } + m.logger.Error(err, "failed to run instrumentation") + } + }() + + return nil +} + +func (m *manager[ProcessGroup, ConfigGroup]) startTrackInstrumentation(pid int, inst Instrumentation, processGroup ProcessGroup, configGroup ConfigGroup) { + instDetails := &instrumentationDetails[ProcessGroup, ConfigGroup]{ + inst: inst, + pg: processGroup, + cg: configGroup, + } + m.detailsByPid[pid] = instDetails + + if _, found := m.detailsByWorkload[configGroup]; !found { + // first instrumentation for this workload + m.detailsByWorkload[configGroup] = map[int]*instrumentationDetails[ProcessGroup, ConfigGroup]{pid: instDetails} + } else { + m.detailsByWorkload[configGroup][pid] = instDetails + } +} + +func (m *manager[ProcessGroup, ConfigGroup]) stopTrackInstrumentation(pid int) { + details, ok := m.detailsByPid[pid] + if !ok { + return + } + workloadConfigID := details.cg + + delete(m.detailsByPid, pid) + delete(m.detailsByWorkload[workloadConfigID], pid) + + if len(m.detailsByWorkload[workloadConfigID]) == 0 { + delete(m.detailsByWorkload, workloadConfigID) + } +} + +func (m *manager[ProcessGroup, ConfigGroup]) applyInstrumentationConfigurationForSDK(ctx context.Context, configGroup ConfigGroup, config Config) error { + var err error + + configGroupInstrumentations, ok := m.detailsByWorkload[configGroup] + if !ok { + return nil + } + + for _, instDetails := range configGroupInstrumentations { + m.logger.Info("applying configuration to instrumentation", "process group details", instDetails.pg, "configGroup", configGroup) + applyErr := instDetails.inst.ApplyConfig(ctx, config) + err = errors.Join(err, applyErr) + } + return err +} diff --git a/instrumentation/types.go b/instrumentation/types.go new file mode 100644 index 000000000..9b734e592 --- /dev/null +++ b/instrumentation/types.go @@ -0,0 +1,93 @@ +package instrumentation + +import ( + "context" + "fmt" + + "github.com/odigos-io/odigos/common" + "github.com/odigos-io/odigos/instrumentation/detector" +) + +// OtelDistribution is a customized version of an OpenTelemetry component. +// see https://opentelemetry.io/docs/concepts/distributions and https://github.com/odigos-io/odigos/pull/1776#discussion_r1853367917 for more information. +// TODO: This should be moved to a common root package, since it will require a bigger refactor across multiple components, +// we use this local definition for now. +type OtelDistribution struct { + Language common.ProgrammingLanguage + OtelSdk common.OtelSdk +} + +// ProcessGroup represents a group of processes that are managed together by the hosting platform. +// It may include different information depending on the platform (Kubernetes, VM, etc). +// +// For example consider an app which is launched by a bash script, the script launches a python process. +// The process may create different child processes, and the bash script may launch multiple python processes. +// In this case, the process group may include the bash script, the python process, and the child processes. +type ProcessGroup interface { + fmt.Stringer +} + +// ConfigGroup is used to represent a group of instrumented processes which can be configured together. +// For example, a Kubernetes deployment with multiple replicas can be considered a ConfigGroup. +// A config group may include multiple process groups, but there is no assumption on a connection between them. +type ConfigGroup interface { + comparable +} + +// ProcessGroupResolver is used to resolve the process group of a process. +type ProcessGroupResolver[processGroup ProcessGroup] interface { + // Resolve will classify the process into a process group. + // Those process group details may be used for future calls when reporting the status of the instrumentation. + // or for resolving the configuration group of the process. + Resolve(context.Context, detector.ProcessEvent) (processGroup, error) +} + +// ConfigGroupResolver is used to resolve the configuration group of a process. +type ConfigGroupResolver[processGroup ProcessGroup, configGroup ConfigGroup] interface { + // Resolve will classify the process into a configuration group. + // The Otel Distribution is resolved in the time of calling this function, and may be used + // to determine the configuration group. + Resolve(context.Context, processGroup, OtelDistribution) (configGroup, error) +} + +// Reporter is used to report the status of the instrumentation. +// It is called at different stages of the instrumentation lifecycle. +type Reporter[processGroup ProcessGroup] interface { + // OnInit is called when the instrumentation is initialized. + // The error parameter will be nil if the instrumentation was initialized successfully. + OnInit(ctx context.Context, pid int, err error, pg processGroup) error + + // OnLoad is called after an instrumentation is loaded successfully or failed to load. + // The error parameter will be nil if the instrumentation was loaded successfully. + OnLoad(ctx context.Context, pid int, err error, pg processGroup) error + + // OnRun is called after the instrumentation stops running. + // An error may report a fatal error during the instrumentation run, or a closing error + // which happened during the closing of the instrumentation. + OnRun(ctx context.Context, pid int, err error, pg processGroup) error + + // OnExit is called when the instrumented process exits, and the instrumentation has already been stopped. + // For a reported which persists the instrumentation state, this is the time to clean up the state. + OnExit(ctx context.Context, pid int, pg processGroup) error +} + +// DistributionMatcher is used to match a process to an Otel Distribution. +type DistributionMatcher[processGroup ProcessGroup] interface { + // Distribution will match a process to an Otel Distribution. + Distribution(context.Context, processGroup) (OtelDistribution, error) +} + +// SettingsGetter is used to fetch the initial settings of an instrumentation. +type SettingsGetter[processGroup ProcessGroup] interface { + // GetSettings will fetch the initial settings of an instrumentation. + Settings(context.Context, processGroup, OtelDistribution) (Settings, error) +} + +// Handler is used to classify, report and configure instrumentations. +type Handler[processGroup ProcessGroup, configGroup comparable] struct { + ProcessGroupResolver ProcessGroupResolver[processGroup] + ConfigGroupResolver ConfigGroupResolver[processGroup, configGroup] + Reporter Reporter[processGroup] + DistributionMatcher DistributionMatcher[processGroup] + SettingsGetter SettingsGetter[processGroup] +} diff --git a/odiglet/Dockerfile b/odiglet/Dockerfile index dc1ff85fc..e3dfa774a 100644 --- a/odiglet/Dockerfile +++ b/odiglet/Dockerfile @@ -82,6 +82,7 @@ COPY common/ common/ COPY k8sutils/ k8sutils/ COPY procdiscovery/ procdiscovery/ COPY opampserver/ opampserver/ +COPY instrumentation/ instrumentation/ WORKDIR /go/src/github.com/odigos-io/odigos/odiglet COPY odiglet/ . diff --git a/odiglet/cmd/main.go b/odiglet/cmd/main.go index 719d11feb..3dd0e0903 100644 --- a/odiglet/cmd/main.go +++ b/odiglet/cmd/main.go @@ -12,6 +12,7 @@ import ( "github.com/kubevirt/device-plugin-manager/pkg/dpm" "github.com/odigos-io/odigos/common" + commonInstrumentation "github.com/odigos-io/odigos/instrumentation" k8senv "github.com/odigos-io/odigos/k8sutils/pkg/env" "github.com/odigos-io/odigos/odiglet/pkg/env" "github.com/odigos-io/odigos/odiglet/pkg/instrumentation" @@ -42,10 +43,14 @@ func odigletInitPhase() { type odiglet struct { clientset *kubernetes.Clientset mgr ctrl.Manager - ebpfManager *ebpf.Manager - configUpdates chan<- ebpf.ConfigUpdate + ebpfManager commonInstrumentation.Manager + configUpdates chan<- commonInstrumentation.ConfigUpdate[ebpf.K8sConfigGroup] } +const ( + configUpdatesBufferSize = 10 +) + func newOdiglet() (*odiglet, error) { // Init Kubernetes API client cfg, err := rest.InClusterConfig() @@ -63,21 +68,22 @@ func newOdiglet() (*odiglet, error) { return nil, fmt.Errorf("Failed to create controller-runtime manager %w", err) } + configUpdates := make(chan commonInstrumentation.ConfigUpdate[ebpf.K8sConfigGroup], configUpdatesBufferSize) ebpfManager, err := ebpf.NewManager( mgr.GetClient(), log.Logger, - map[ebpf.OtelDistribution]ebpf.Factory{ - ebpf.OtelDistribution{ + map[commonInstrumentation.OtelDistribution]commonInstrumentation.Factory{ + commonInstrumentation.OtelDistribution{ Language: common.GoProgrammingLanguage, OtelSdk: common.OtelSdkEbpfCommunity, }: sdks.NewGoInstrumentationFactory(), }, + configUpdates, ) if err != nil { return nil, fmt.Errorf("Failed to create ebpf manager %w", err) } - configUpdates := ebpfManager.ConfigUpdates() err = kube.SetupWithManager(mgr, nil, clientset, configUpdates) if err != nil { return nil, fmt.Errorf("Failed to setup controller-runtime manager %w", err) @@ -123,7 +129,7 @@ func (o *odiglet) run(ctx context.Context) { if err != nil { log.Logger.Error(err, "Failed to run ebpf manager") } - log.Logger.V(0).Info("Ebpf manager exited") + log.Logger.V(0).Info("eBPF manager exited") }() // start OpAmp server diff --git a/odiglet/debug.Dockerfile b/odiglet/debug.Dockerfile index 1ce17a41b..369bde3b8 100644 --- a/odiglet/debug.Dockerfile +++ b/odiglet/debug.Dockerfile @@ -71,6 +71,7 @@ COPY common/ common/ COPY k8sutils/ k8sutils/ COPY procdiscovery/ procdiscovery/ COPY opampserver/ opampserver/ +COPY instrumentation/ instrumentation/ WORKDIR /go/src/github.com/odigos-io/odigos/odiglet COPY odiglet/ . diff --git a/odiglet/go.mod b/odiglet/go.mod index 91c2b0b53..20ec6169e 100644 --- a/odiglet/go.mod +++ b/odiglet/go.mod @@ -9,18 +9,18 @@ require ( github.com/kubevirt/device-plugin-manager v1.19.5 github.com/moby/sys/mountinfo v0.7.2 github.com/odigos-io/odigos/api v0.0.0 - github.com/odigos-io/odigos/common v1.0.70 + github.com/odigos-io/odigos/common v0.0.0 + github.com/odigos-io/odigos/instrumentation v0.0.0 github.com/odigos-io/odigos/k8sutils v0.0.0 github.com/odigos-io/odigos/opampserver v0.0.0 github.com/odigos-io/odigos/procdiscovery v0.0.0 github.com/odigos-io/opentelemetry-zap-bridge v0.0.5 - github.com/odigos-io/runtime-detector v0.0.3 + github.com/odigos-io/runtime-detector v0.0.4 github.com/stretchr/testify v1.10.0 go.opentelemetry.io/auto v0.19.0-alpha - go.opentelemetry.io/otel v1.32.0 + go.opentelemetry.io/otel v1.33.0 go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.32.0 go.uber.org/zap v1.27.0 - golang.org/x/sync v0.10.0 google.golang.org/grpc v1.68.1 k8s.io/api v0.31.3 k8s.io/apimachinery v0.31.3 @@ -30,27 +30,26 @@ require ( ) require ( - github.com/agoda-com/opentelemetry-logs-go v0.4.0 // indirect + github.com/agoda-com/opentelemetry-logs-go v0.5.1 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cilium/ebpf v0.16.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect - github.com/emicklei/go-restful/v3 v3.11.0 // indirect + github.com/emicklei/go-restful/v3 v3.12.1 // indirect github.com/evanphx/json-patch/v5 v5.9.0 // indirect - github.com/fatih/color v1.15.0 // indirect - github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/fsnotify/fsnotify v1.8.0 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/go-logr/stdr v1.2.2 // indirect - github.com/go-openapi/jsonpointer v0.19.6 // indirect - github.com/go-openapi/jsonreference v0.20.2 // indirect - github.com/go-openapi/swag v0.22.4 // indirect - github.com/goccy/go-yaml v1.11.3 // indirect + github.com/go-openapi/jsonpointer v0.21.0 // indirect + github.com/go-openapi/jsonreference v0.21.0 // indirect + github.com/go-openapi/swag v0.23.0 // indirect + github.com/goccy/go-yaml v1.15.9 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/glog v1.2.2 // indirect + github.com/golang/glog v1.2.3 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // indirect - github.com/google/gnostic-models v0.6.8 // indirect + github.com/google/gnostic-models v0.6.9 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 // indirect @@ -60,8 +59,6 @@ require ( github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.17.11 // indirect github.com/mailru/easyjson v0.7.7 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.19 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect @@ -73,6 +70,7 @@ require ( github.com/prometheus/procfs v0.15.1 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/x448/float16 v0.8.4 // indirect + go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/collector/pdata v1.21.0 // indirect go.opentelemetry.io/contrib/bridges/prometheus v0.57.0 // indirect go.opentelemetry.io/contrib/exporters/autoexport v0.57.0 // indirect @@ -87,42 +85,42 @@ require ( go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.32.0 // indirect go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.32.0 // indirect go.opentelemetry.io/otel/log v0.8.0 // indirect - go.opentelemetry.io/otel/metric v1.32.0 // indirect + go.opentelemetry.io/otel/metric v1.33.0 // indirect go.opentelemetry.io/otel/sdk v1.32.0 // indirect go.opentelemetry.io/otel/sdk/log v0.8.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.32.0 // indirect - go.opentelemetry.io/otel/trace v1.32.0 // indirect + go.opentelemetry.io/otel/trace v1.33.0 // indirect go.opentelemetry.io/proto/otlp v1.4.0 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/arch v0.12.0 // indirect - golang.org/x/exp v0.0.0-20241204233417-43b7b7cde48d // indirect + golang.org/x/exp v0.0.0-20241210194714-1829a127f884 // indirect golang.org/x/net v0.32.0 // indirect golang.org/x/oauth2 v0.24.0 // indirect + golang.org/x/sync v0.10.0 // indirect golang.org/x/sys v0.28.0 // indirect golang.org/x/term v0.27.0 // indirect golang.org/x/text v0.21.0 // indirect - golang.org/x/time v0.3.0 // indirect - golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect + golang.org/x/time v0.8.0 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20241202173237-19429a94021a // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 // indirect google.golang.org/protobuf v1.35.2 // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/apiextensions-apiserver v0.31.0 // indirect + k8s.io/apiextensions-apiserver v0.31.3 // indirect k8s.io/klog/v2 v2.130.1 // indirect - k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect - k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 // indirect - sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect + k8s.io/kube-openapi v0.0.0-20241212222426-2c72e554b1e7 // indirect + k8s.io/utils v0.0.0-20241210054802-24370beab758 // indirect + sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.5.0 // indirect sigs.k8s.io/yaml v1.4.0 // indirect ) replace ( github.com/odigos-io/odigos/api => ../api github.com/odigos-io/odigos/common => ../common + github.com/odigos-io/odigos/instrumentation => ../instrumentation github.com/odigos-io/odigos/k8sutils => ../k8sutils github.com/odigos-io/odigos/opampserver => ../opampserver github.com/odigos-io/odigos/procdiscovery => ../procdiscovery diff --git a/odiglet/go.sum b/odiglet/go.sum index 4749c9bb6..c6754d012 100644 --- a/odiglet/go.sum +++ b/odiglet/go.sum @@ -28,8 +28,8 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/agoda-com/opentelemetry-logs-go v0.4.0 h1:XLPOlLHLOND2/VrL69TWSy6blCZnypV37t1MjfILksI= -github.com/agoda-com/opentelemetry-logs-go v0.4.0/go.mod h1:CeDuVaK9yCWN+8UjOW8AciYJE0rl7K/mw4ejBntGYkc= +github.com/agoda-com/opentelemetry-logs-go v0.5.1 h1:6iQrLaY4M0glBZb/xVN559qQutK4V+HJ/mB1cbwaX3c= +github.com/agoda-com/opentelemetry-logs-go v0.5.1/go.mod h1:35B5ypjX5pkVCPJR01i6owJSYWe8cnbWLpEyHgAGD/E= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= @@ -52,7 +52,6 @@ github.com/cilium/ebpf v0.16.0 h1:+BiEnHL6Z7lXnlGUsXQPPAE7+kenAd4ES8MQ5min0Ok= github.com/cilium/ebpf v0.16.0/go.mod h1:L7u2Blt2jMM/vLAVgjxluxtBKlz3/GWjB0dMOEngfwE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 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= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= @@ -62,8 +61,8 @@ github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZ github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= -github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= -github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emicklei/go-restful/v3 v3.12.1 h1:PJMDIM/ak7btuL8Ex0iYET9hxM3CI2sjZtzpL63nKAU= +github.com/emicklei/go-restful/v3 v3.12.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -72,12 +71,10 @@ github.com/evanphx/json-patch v4.9.0+incompatible h1:kLcOMZeuLAJvL2BPWLMIj5oaZQo github.com/evanphx/json-patch v4.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.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= -github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -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/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= +github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= @@ -96,36 +93,29 @@ github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= -github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= -github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= +github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= +github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= -github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= -github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= +github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= +github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= -github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= -github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU= -github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= -github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= -github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= -github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= -github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= -github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE= -github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= +github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= +github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI= github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= -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/goccy/go-yaml v1.15.9 h1:500CYajdgpK4Smqrf86u7VMZuj/bFt2ghdff9D/nQYc= +github.com/goccy/go-yaml v1.15.9/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.2.2 h1:1+mZ9upx1Dh6FmUTFR1naJ77miKiXgALjWOZ3NVFPmY= -github.com/golang/glog v1.2.2/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= +github.com/golang/glog v1.2.3 h1:oDTdz9f5VGVVNGu/Q7UXKWYsD0873HXLHdJUNBsSEKM= +github.com/golang/glog v1.2.3/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= @@ -148,8 +138,8 @@ github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= -github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= +github.com/google/gnostic-models v0.6.9 h1:MU/8wDLif2qCXZmzncUQ/BOfxWfthHi63KqpoNbWqVw= +github.com/google/gnostic-models v0.6.9/go.mod h1:CiWsm0s6BSQd1hRn8/QmxqB6BesYcbSZxsz9b0KuDBw= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -166,8 +156,8 @@ github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXi github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af h1:kmjWCqn2qkEml422C2Rrd27c3VGxi6a/6HNq8QmHRKM= -github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= +github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 h1:FKHo8hFI3A+7w0aUQuYXQ+6EN5stWmeY/AZqtM8xk9k= +github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= @@ -210,7 +200,6 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxv github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -221,16 +210,9 @@ github.com/kubevirt/device-plugin-manager v1.19.5 h1:nA9rPpQyWBNyrpqaZe2aW4PZfTB github.com/kubevirt/device-plugin-manager v1.19.5/go.mod h1:gPIAptDNdxXBVbq4I2eNPlLy8ZHbd24KpjNLWmpfQuU= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= -github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= -github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= -github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g= @@ -256,8 +238,8 @@ github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/odigos-io/opentelemetry-zap-bridge v0.0.5 h1:UDEKtgab42nGVSvA/F3lLKUYFPETtpl7kpxM9BKBlWk= github.com/odigos-io/opentelemetry-zap-bridge v0.0.5/go.mod h1:K98wHhktQ6vCTqeFztcpBDtPTe88vxVgZFlbeGobt24= -github.com/odigos-io/runtime-detector v0.0.3 h1:hUsdSmsPJ4ZrXofEzeNsfiids99RN+O6XcKxsgpZirE= -github.com/odigos-io/runtime-detector v0.0.3/go.mod h1:m8GfdG6pET0K/8aoZwnX+MkYz8oVroKs8HzRnkuJWt4= +github.com/odigos-io/runtime-detector v0.0.4 h1:q4yap5yTApkFFSRdwnU6NZeV+IbzEzWJZv6IEVCVKyE= +github.com/odigos-io/runtime-detector v0.0.4/go.mod h1:m8GfdG6pET0K/8aoZwnX+MkYz8oVroKs8HzRnkuJWt4= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= @@ -314,14 +296,9 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/tj/assert v0.0.3 h1:Df/BlaZ20mq6kuai7f5z2TvPFiwC3xaWJSDQNiIS3Rk= @@ -335,14 +312,16 @@ go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opentelemetry.io/auto v0.19.0-alpha h1:TsJVpNtI0g/N/FT/rv7jaEqctY4kJz5yPfFuol24IS8= go.opentelemetry.io/auto v0.19.0-alpha/go.mod h1:Olz9mFDiXanGQxa4qqWYO6CV5cVFFxC5tPZzu2W3lxk= +go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= +go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/collector/pdata v1.21.0 h1:PG+UbiFMJ35X/WcAR7Rf/PWmWtRdW0aHlOidsR6c5MA= go.opentelemetry.io/collector/pdata v1.21.0/go.mod h1:GKb1/zocKJMvxKbS+sl0W85lxhYBTFJ6h6I1tphVyDU= go.opentelemetry.io/contrib/bridges/prometheus v0.57.0 h1:UW0+QyeyBVhn+COBec3nGhfnFe5lwB0ic1JBVjzhk0w= go.opentelemetry.io/contrib/bridges/prometheus v0.57.0/go.mod h1:ppciCHRLsyCio54qbzQv0E4Jyth/fLWDTJYfvWpcSVk= go.opentelemetry.io/contrib/exporters/autoexport v0.57.0 h1:jmTVJ86dP60C01K3slFQa2NQ/Aoi7zA+wy7vMOKD9H4= go.opentelemetry.io/contrib/exporters/autoexport v0.57.0/go.mod h1:EJBheUMttD/lABFyLXhce47Wr6DPWYReCzaZiXadH7g= -go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U= -go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg= +go.opentelemetry.io/otel v1.33.0 h1:/FerN9bax5LoK51X/sI0SVYrjSE0/yUL7DpxW4K3FWw= +go.opentelemetry.io/otel v1.33.0/go.mod h1:SUUkR6csvUQl+yjReHu5uM3EtVV7MBm5FHKRlNx4I8I= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.8.0 h1:WzNab7hOOLzdDF/EoWCt4glhrbMPVMOO5JYTmpz36Ls= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.8.0/go.mod h1:hKvJwTzJdp90Vh7p6q/9PAOd55dI6WA6sWj62a/JvSs= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.8.0 h1:S+LdBGiQXtJdowoJoQPEtI52syEP/JYBUpjO49EQhV8= @@ -367,16 +346,16 @@ go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.32.0 h1:cC2yDI3IQd0Udsu go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.32.0/go.mod h1:2PD5Ex6z8CFzDbTdOlwyNIUywRr1DN0ospafJM1wJ+s= go.opentelemetry.io/otel/log v0.8.0 h1:egZ8vV5atrUWUbnSsHn6vB8R21G2wrKqNiDt3iWertk= go.opentelemetry.io/otel/log v0.8.0/go.mod h1:M9qvDdUTRCopJcGRKg57+JSQ9LgLBrwwfC32epk5NX8= -go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M= -go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8= +go.opentelemetry.io/otel/metric v1.33.0 h1:r+JOocAyeRVXD8lZpjdQjzMadVZp2M4WmQ+5WtEnklQ= +go.opentelemetry.io/otel/metric v1.33.0/go.mod h1:L9+Fyctbp6HFTddIxClbQkjtubW6O9QS3Ann/M82u6M= go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4= go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU= go.opentelemetry.io/otel/sdk/log v0.8.0 h1:zg7GUYXqxk1jnGF/dTdLPrK06xJdrXgqgFLnI4Crxvs= go.opentelemetry.io/otel/sdk/log v0.8.0/go.mod h1:50iXr0UVwQrYS45KbruFrEt4LvAdCaWWgIrsN3ZQggo= go.opentelemetry.io/otel/sdk/metric v1.32.0 h1:rZvFnvmvawYb0alrYkjraqJq0Z4ZUJAiyYCU9snn1CU= go.opentelemetry.io/otel/sdk/metric v1.32.0/go.mod h1:PWeZlq0zt9YkYAp3gjKZ0eicRYvOh1Gd+X99x6GHpCQ= -go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM= -go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8= +go.opentelemetry.io/otel/trace v1.33.0 h1:cCJuF7LRjUFso9LPnEAHJDB2pqzp+hbO8eu1qqW2d/s= +go.opentelemetry.io/otel/trace v1.33.0/go.mod h1:uIcdVUZMpTAmz0tI1z04GoVSezK37CbGV4fr1f2nBck= go.opentelemetry.io/proto/otlp v1.4.0 h1:TA9WRvW6zMwP+Ssb6fLoUIuirti1gGbP28GcKG1jgeg= go.opentelemetry.io/proto/otlp v1.4.0/go.mod h1:PPBWZIP98o2ElSqI35IHfu7hIhSwvc5N38Jw8pXuGFY= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= @@ -397,15 +376,13 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.30.0 h1:RwoQn3GkWiMkzlX562cLB7OxWvjH1L8xutO2WoJcRoY= -golang.org/x/crypto v0.30.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20241204233417-43b7b7cde48d h1:0olWaB5pg3+oychR51GUVCEsGkeCU/2JxjBgIo4f3M0= -golang.org/x/exp v0.0.0-20241204233417-43b7b7cde48d/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c= +golang.org/x/exp v0.0.0-20241210194714-1829a127f884 h1:Y/Mj/94zIQQGHVSv1tTtQBDaQaJe62U9bkDZKKyhPCU= +golang.org/x/exp v0.0.0-20241210194714-1829a127f884/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -484,8 +461,6 @@ golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200917073148-efd3b9a0ff20/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= @@ -499,8 +474,8 @@ golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= -golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg= +golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -530,8 +505,6 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= 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/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= @@ -555,10 +528,10 @@ google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBr google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200916143405-f6a2fa72f0c4/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto/googleapis/api v0.0.0-20241202173237-19429a94021a h1:OAiGFfOiA0v9MRYsSidp3ubZaBnteRUyn3xB2ZQ5G/E= -google.golang.org/genproto/googleapis/api v0.0.0-20241202173237-19429a94021a/go.mod h1:jehYqy3+AhJU9ve55aNOaSml7wUXjF9x6z2LcCfpAhY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a h1:hgh8P4EuoxpsuKMXX/To36nOFD7vixReXgn8lPGnt+o= -google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU= +google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576 h1:CkkIfIt50+lT6NHAVoRYEyAvQGFM7xEwXUUywFvEb3Q= +google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576/go.mod h1:1R3kvZ1dtP3+4p4d3G8uJ8rFk/fWlScl38vanWACI08= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 h1:8ZmaLZE4XWrtU3MyClkYqqtl6Oegr3235h7jxsDyqCY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -603,7 +576,6 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= @@ -616,8 +588,8 @@ honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt k8s.io/api v0.19.2/go.mod h1:IQpK0zFQ1xc5iNIQPqzgoOwuFugaYHK4iCknlAQP9nI= k8s.io/api v0.31.3 h1:umzm5o8lFbdN/hIXbrK9oRpOproJO62CV1zqxXrLgk8= k8s.io/api v0.31.3/go.mod h1:UJrkIp9pnMOI9K2nlL6vwpxRzzEX5sWgn8kGQe92kCE= -k8s.io/apiextensions-apiserver v0.31.0 h1:fZgCVhGwsclj3qCw1buVXCV6khjRzKC5eCFt24kyLSk= -k8s.io/apiextensions-apiserver v0.31.0/go.mod h1:b9aMDEYaEe5sdK+1T0KU78ApR/5ZVp4i56VacZYEHxk= +k8s.io/apiextensions-apiserver v0.31.3 h1:+GFGj2qFiU7rGCsA5o+p/rul1OQIq6oYpQw4+u+nciE= +k8s.io/apiextensions-apiserver v0.31.3/go.mod h1:2DSpFhUZZJmn/cr/RweH1cEVVbzFw9YBu4T+U3mf1e4= k8s.io/apimachinery v0.19.2/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA= k8s.io/apimachinery v0.31.3 h1:6l0WhcYgasZ/wk9ktLq5vLaoXJJr5ts6lkaQzgeYPq4= k8s.io/apimachinery v0.31.3/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= @@ -631,22 +603,22 @@ k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o= -k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag= -k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98= +k8s.io/kube-openapi v0.0.0-20241212222426-2c72e554b1e7 h1:hcha5B1kVACrLujCKLbr8XWMxCxzQx42DY8QKYJrDLg= +k8s.io/kube-openapi v0.0.0-20241212222426-2c72e554b1e7/go.mod h1:GewRfANuJ70iYzvn+i4lezLDAFzvjxZYK1gn1lWcfas= k8s.io/kubelet v0.19.2/go.mod h1:FHHoByVWzh6kNaarXaDPAa751Oz6REcOVRyFT84L1Is= k8s.io/kubelet v0.31.3 h1:DIXRAmvVGp42mV2vpA1GCLU6oO8who0/vp3Oq6kSpbI= k8s.io/kubelet v0.31.3/go.mod h1:KSdbEfNy5VzqUlAHlytA/fH12s+sE1u8fb/8JY9sL/8= k8s.io/utils v0.0.0-20200729134348-d5654de09c73/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A= -k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +k8s.io/utils v0.0.0-20241210054802-24370beab758 h1:sdbE21q2nlQtFh65saZY+rRM6x6aJJI8IUa1AmH/qa0= +k8s.io/utils v0.0.0-20241210054802-24370beab758/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= sigs.k8s.io/controller-runtime v0.19.3 h1:XO2GvC9OPftRst6xWCpTgBZO04S2cbp0Qqkj8bX1sPw= sigs.k8s.io/controller-runtime v0.19.3/go.mod h1:j4j87DqtsThvwTv5/Tc5NFRyyF/RF0ip4+62tbTSIUM= -sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= -sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE= +sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= -sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= -sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= +sigs.k8s.io/structured-merge-diff/v4 v4.5.0 h1:nbCitCK2hfnhyiKo6uf2HxUPTCodY6Qaf85SbDIaMBk= +sigs.k8s.io/structured-merge-diff/v4 v4.5.0/go.mod h1:N8f93tFZh9U6vpxwRArLiikrE5/2tiu1w1AGfACIGE4= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= diff --git a/odiglet/pkg/detector/detector.go b/odiglet/pkg/detector/detector.go index d1d9a477c..4646b902a 100644 --- a/odiglet/pkg/detector/detector.go +++ b/odiglet/pkg/detector/detector.go @@ -1,7 +1,6 @@ package detector import ( - "context" "log/slog" "github.com/go-logr/logr" @@ -11,16 +10,7 @@ import ( "github.com/odigos-io/runtime-detector" ) -type ProcessEvent = detector.ProcessEvent - -type Detector = detector.Detector - -const ( - ProcessExecEvent = detector.ProcessExecEvent - ProcessExitEvent = detector.ProcessExitEvent -) - -func NewK8SProcDetector(ctx context.Context, logger logr.Logger, events chan<- ProcessEvent) (*detector.Detector, error) { +func K8sDetectorOptions(logger logr.Logger) []detector.DetectorOption { sLogger := slog.New(logr.ToSlogHandler(logger)) opts := []detector.DetectorOption{ @@ -28,13 +18,8 @@ func NewK8SProcDetector(ctx context.Context, logger logr.Logger, events chan<- P detector.WithEnvironments(relevantEnvVars()...), detector.WithEnvPrefixFilter(consts.OdigosEnvVarPodName), } - detector, err := detector.NewDetector(ctx, events, opts...) - - if err != nil { - return nil, err - } - return detector, nil + return opts } func relevantEnvVars() []string { diff --git a/odiglet/pkg/ebpf/common.go b/odiglet/pkg/ebpf/common.go new file mode 100644 index 000000000..b39a390d7 --- /dev/null +++ b/odiglet/pkg/ebpf/common.go @@ -0,0 +1,48 @@ +package ebpf + +import ( + "github.com/go-logr/logr" + "github.com/odigos-io/odigos/instrumentation" + "github.com/odigos-io/odigos/odiglet/pkg/detector" + + "sigs.k8s.io/controller-runtime/pkg/client" +) + +// NewManager creates a new instrumentation manager for eBPF which is configured to work with Kubernetes. +func NewManager(client client.Client, logger logr.Logger, factories map[instrumentation.OtelDistribution]instrumentation.Factory, configUpdates <-chan instrumentation.ConfigUpdate[K8sConfigGroup]) (instrumentation.Manager, error) { + managerOpts := instrumentation.ManagerOptions[K8sProcessGroup, K8sConfigGroup]{ + Logger: logger, + Factories: factories, + Handler: newHandler(client), + DetectorOptions: detector.K8sDetectorOptions(logger), + ConfigUpdates: configUpdates, + } + + manager, err := instrumentation.NewManager(managerOpts) + if err != nil { + return nil, err + } + + return manager, nil +} + +func newHandler(client client.Client) *instrumentation.Handler[K8sProcessGroup, K8sConfigGroup] { + reporter := &k8sReporter{ + client: client, + } + processGroupResolver := &k8sDetailsResolver{ + client: client, + } + configGroupResolver := &k8sConfigGroupResolver{} + settingsGetter := &k8sSettingsGetter{ + client: client, + } + distributionMatcher := &podDeviceDistributionMatcher{} + return &instrumentation.Handler[K8sProcessGroup, K8sConfigGroup]{ + ProcessGroupResolver: processGroupResolver, + ConfigGroupResolver: configGroupResolver, + Reporter: reporter, + DistributionMatcher: distributionMatcher, + SettingsGetter: settingsGetter, + } +} diff --git a/odiglet/pkg/ebpf/distribution_matcher.go b/odiglet/pkg/ebpf/distribution_matcher.go new file mode 100644 index 000000000..624e31e63 --- /dev/null +++ b/odiglet/pkg/ebpf/distribution_matcher.go @@ -0,0 +1,23 @@ +package ebpf + +import ( + "context" + "fmt" + + "github.com/odigos-io/odigos/instrumentation" + odgiosK8s "github.com/odigos-io/odigos/k8sutils/pkg/container" +) + +type podDeviceDistributionMatcher struct{} + +func (dm *podDeviceDistributionMatcher) Distribution(ctx context.Context, e K8sProcessGroup) (instrumentation.OtelDistribution, error) { + // get the language and sdk for this process event + // based on the pod spec and the container name from the process event + // TODO: We should have all the required information in the process event + // to determine the language - hence in the future we can improve this + lang, sdk, err := odgiosK8s.LanguageSdkFromPodContainer(e.pod, e.containerName) + if err != nil { + return instrumentation.OtelDistribution{}, fmt.Errorf("failed to get language and sdk: %w", err) + } + return instrumentation.OtelDistribution{Language: lang, OtelSdk: sdk}, nil +} diff --git a/odiglet/pkg/ebpf/manager.go b/odiglet/pkg/ebpf/manager.go deleted file mode 100644 index bc31f596c..000000000 --- a/odiglet/pkg/ebpf/manager.go +++ /dev/null @@ -1,434 +0,0 @@ -package ebpf - -import ( - "context" - "errors" - "fmt" - - "golang.org/x/sync/errgroup" - - "github.com/go-logr/logr" - odigosv1 "github.com/odigos-io/odigos/api/odigos/v1alpha1" - "github.com/odigos-io/odigos/common" - "github.com/odigos-io/odigos/k8sutils/pkg/consts" - odgiosK8s "github.com/odigos-io/odigos/k8sutils/pkg/container" - instance "github.com/odigos-io/odigos/k8sutils/pkg/instrumentation_instance" - "github.com/odigos-io/odigos/k8sutils/pkg/workload" - workloadUtils "github.com/odigos-io/odigos/k8sutils/pkg/workload" - "github.com/odigos-io/odigos/odiglet/pkg/detector" - "github.com/odigos-io/odigos/odiglet/pkg/kube/utils" - corev1 "k8s.io/api/core/v1" - apierrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -var ( - ErrNoInstrumentationFactory = errors.New("no ebpf factory found") -) - -const ( - configUpdatesBufferSize = 10 -) - -type errRequiredEnvVarNotFound struct { - envVarName string -} - -func (e *errRequiredEnvVarNotFound) Error() string { - return fmt.Sprintf("required environment variable not found: %s", e.envVarName) -} - -var _ error = &errRequiredEnvVarNotFound{} - -var ( - errContainerNameNotReported = &errRequiredEnvVarNotFound{envVarName: consts.OdigosEnvVarContainerName} - errPodNameNotReported = &errRequiredEnvVarNotFound{envVarName: consts.OdigosEnvVarPodName} - errPodNameSpaceNotReported = &errRequiredEnvVarNotFound{envVarName: consts.OdigosEnvVarNamespace} -) - -type InstrumentationStatusReason string - -const ( - FailedToLoad InstrumentationStatusReason = "FailedToLoad" - FailedToInitialize InstrumentationStatusReason = "FailedToInitialize" - LoadedSuccessfully InstrumentationStatusReason = "LoadedSuccessfully" - FailedToRun InstrumentationStatusReason = "FailedToRun" -) - -type InstrumentationHealth bool - -const ( - InstrumentationHealthy InstrumentationHealth = true - InstrumentationUnhealthy InstrumentationHealth = false -) - -type ConfigUpdate struct { - PodWorkload workload.PodWorkload - Config *odigosv1.InstrumentationConfig -} - -type instrumentationDetails struct { - inst Instrumentation - pod types.NamespacedName - configID workloadConfigID -} - -// workloadConfigID is used to identify a workload and its language for configuration updates -type workloadConfigID struct { - podWorkload workload.PodWorkload - lang common.ProgrammingLanguage -} - -type Manager struct { - // channel for receiving process events, - // used to detect new processes and process exits, and handle their instrumentation accordingly. - procEvents <-chan detector.ProcessEvent - detector *detector.Detector - client client.Client - factories map[OtelDistribution]Factory - logger logr.Logger - - // all the active instrumentations by pid, - // this map is not concurrent safe, so it should be accessed only from the main event loop - detailsByPid map[int]*instrumentationDetails - - // active instrumentations by workload, and aggregated by pid - // this map is not concurrent safe, so it should be accessed only from the main event loop - detailsByWorkload map[workloadConfigID]map[int]*instrumentationDetails - - configUpdates chan ConfigUpdate -} - -func NewManager(client client.Client, logger logr.Logger, factories map[OtelDistribution]Factory) (*Manager, error) { - procEvents := make(chan detector.ProcessEvent) - detector, err := detector.NewK8SProcDetector(context.Background(), logger, procEvents) - if err != nil { - return nil, fmt.Errorf("failed to create process detector: %w", err) - } - - return &Manager{ - procEvents: procEvents, - detector: detector, - client: client, - factories: factories, - logger: logger.WithName("ebpf-instrumentation-manager"), - detailsByPid: make(map[int]*instrumentationDetails), - detailsByWorkload: map[workloadConfigID]map[int]*instrumentationDetails{}, - configUpdates: make(chan ConfigUpdate, configUpdatesBufferSize), - }, nil -} - -// ConfigUpdates returns a channel for receiving configuration updates for instrumentations -// sending on the channel will add an event to the main event loop to apply the configuration. -// closing this channel is in the responsibility of the caller. -func (m *Manager) ConfigUpdates() chan<- ConfigUpdate { - return m.configUpdates -} - -func (m *Manager) runEventLoop(ctx context.Context) { - // main event loop for handling instrumentations - for { - select { - case <-ctx.Done(): - m.logger.Info("stopping Odiglet instrumentation manager") - for pid, details := range m.detailsByPid { - err := details.inst.Close(ctx) - if err != nil { - m.logger.Error(err, "failed to close instrumentation", "pid", pid) - } - // probably shouldn't remove instrumentation instance here - // as this flow is happening when Odiglet is shutting down - } - m.detailsByPid = nil - m.detailsByWorkload = nil - return - case e := <-m.procEvents: - switch e.EventType { - case detector.ProcessExecEvent: - m.logger.V(1).Info("detected new process", "pid", e.PID, "cmd", e.ExecDetails.CmdLine) - err := m.handleProcessExecEvent(ctx, e) - // ignore the error if no instrumentation factory is found, - // as this is expected for some language and sdk combinations - if err != nil && !errors.Is(err, ErrNoInstrumentationFactory) { - m.logger.Error(err, "failed to handle process exec event") - } - case detector.ProcessExitEvent: - m.cleanInstrumentation(ctx, e.PID) - } - case configUpdate := <-m.configUpdates: - if configUpdate.Config == nil { - m.logger.Info("received nil config update, skipping") - break - } - for _, sdkConfig := range configUpdate.Config.Spec.SdkConfigs { - err := m.applyInstrumentationConfigurationForSDK(ctx, configUpdate.PodWorkload, &sdkConfig) - if err != nil { - m.logger.Error(err, "failed to apply instrumentation configuration") - } - } - } - } -} - -func (m *Manager) Run(ctx context.Context) error { - g, errCtx := errgroup.WithContext(ctx) - - g.Go(func() error { - return m.detector.Run(errCtx) - }) - - g.Go(func() error { - m.runEventLoop(errCtx) - return nil - }) - - err := g.Wait() - return err -} - -func (m *Manager) cleanInstrumentation(ctx context.Context, pid int) { - details, found := m.detailsByPid[pid] - if !found { - m.logger.V(3).Info("no instrumentation found for exiting pid, nothing to clean", "pid", pid) - return - } - - m.logger.Info("cleaning instrumentation resources", "pid", pid) - - err := details.inst.Close(ctx) - if err != nil { - m.logger.Error(err, "failed to close instrumentation") - } - - // remove instrumentation instance - if err = m.client.Delete(ctx, &odigosv1.InstrumentationInstance{ - ObjectMeta: metav1.ObjectMeta{ - Name: instance.InstrumentationInstanceName(details.pod.Name, pid), - Namespace: details.pod.Namespace, - }, - }); err != nil && !apierrors.IsNotFound(err) { - m.logger.Error(err, "error deleting instrumentation instance", "pod", details.pod.Name, "pid", pid) - } - - m.stopTrackInstrumentation(pid) -} - -func (m *Manager) handleProcessExecEvent(ctx context.Context, e detector.ProcessEvent) error { - if _, found := m.detailsByPid[e.PID]; found { - // this can happen if we have multiple exec events for the same pid (chain loading) - // TODO: better handle this? - // this can be done by first closing the existing instrumentation, - // and then creating a new one - m.logger.Info("received exec event for process id which is already instrumented with ebpf, skipping it", "pid", e.PID) - return nil - } - - // get the corresponding pod object for this process event - pod, err := m.podFromProcEvent(ctx, e) - if err != nil { - return fmt.Errorf("failed to get pod from process event: %w", err) - } - - containerName, found := containerNameFromProcEvent(e) - if !found { - return errContainerNameNotReported - } - - // get the language and sdk for this process event - // based on the pod spec and the container name from the process event - // TODO: We should have all the required information in the process event - // to determine the language - hence in the future we can improve this - lang, sdk, err := odgiosK8s.LanguageSdkFromPodContainer(pod, containerName) - if err != nil { - return fmt.Errorf("failed to get language and sdk: %w", err) - } - - factory, found := m.factories[OtelDistribution{Language: lang, OtelSdk: sdk}] - if !found { - return ErrNoInstrumentationFactory - } - - podWorkload, err := workloadUtils.PodWorkloadObjectOrError(ctx, pod) - if err != nil { - return fmt.Errorf("failed to find workload object from pod manifest owners references: %w", err) - } - - // Fetch initial config based on the InstrumentationConfig CR - sdkConfig := m.instrumentationSDKConfig(ctx, podWorkload, lang, types.NamespacedName{Namespace: pod.Namespace, Name: pod.Name}) - // we should always have config for this event. - // if missing, it means that either: - // - the config will be generated later due to reconciliation timing in instrumentor - // - just got deleted and the pod (and the process) will go down soon - // TODO: sync reconcilers so inst config is guaranteed be created before the webhook is enabled - // - // if sdkConfig == nil { - // m.Logger.Info("no sdk config found for language", "language", lang, "pod", pod.Name) - // return nil - // } - - settings := Settings{ - // TODO: respect reported name annotation (if present) - to override the service name - // refactor from opAmp code - ServiceName: podWorkload.Name, - // TODO: add container name - ResourceAttributes: utils.GetResourceAttributes(podWorkload, pod.Name), - InitialConfig: sdkConfig, - } - - inst, err := factory.CreateInstrumentation(ctx, e.PID, settings) - if err != nil { - m.logger.Error(err, "failed to initialize instrumentation", "language", lang, "sdk", sdk) - - // write instrumentation instance CR with error status - err = m.updateInstrumentationInstanceStatus(ctx, pod, containerName, podWorkload, e.PID, InstrumentationUnhealthy, FailedToInitialize, err.Error()) - // TODO: should we return here the initialize error? or the instance write error? or both? - return err - } - - err = inst.Load(ctx) - if err != nil { - m.logger.Error(err, "failed to load instrumentation", "language", lang, "sdk", sdk) - - // write instrumentation instance CR with error status - err = m.updateInstrumentationInstanceStatus(ctx, pod, containerName, podWorkload, e.PID, InstrumentationUnhealthy, FailedToLoad, err.Error()) - // TODO: should we return here the load error? or the instance write error? or both? - return err - } - - m.startTrackInstrumentation(e.PID, lang, inst, types.NamespacedName{Namespace: pod.Namespace, Name: pod.Name}, *podWorkload) - - m.logger.Info("instrumentation loaded", "pid", e.PID, "pod", pod.Name, "container", containerName, "language", lang, "sdk", sdk) - - // write instrumentation instance CR with success status - msg := fmt.Sprintf("Successfully loaded eBPF probes to pod: %s container: %s", pod.Name, containerName) - err = m.updateInstrumentationInstanceStatus(ctx, pod, containerName, podWorkload, e.PID, InstrumentationHealthy, LoadedSuccessfully, msg) - if err != nil { - m.logger.Error(err, "failed to update instrumentation instance for successful load") - } - - go func() { - err := inst.Run(ctx) - if err != nil && !errors.Is(err, context.Canceled) { - m.logger.Error(err, "failed to run instrumentation") - err = m.updateInstrumentationInstanceStatus(ctx, pod, containerName, podWorkload, e.PID, InstrumentationUnhealthy, FailedToRun, err.Error()) - if err != nil { - m.logger.Error(err, "failed to update instrumentation instance for failed instrumentation run") - } - } - }() - - return nil -} - -func (m *Manager) startTrackInstrumentation(pid int, lang common.ProgrammingLanguage, inst Instrumentation, pod types.NamespacedName, podWorkload workload.PodWorkload) { - workloadConfigID := workloadConfigID{ - podWorkload: podWorkload, - lang: lang, - } - - details := &instrumentationDetails{ - inst: inst, - pod: pod, - configID: workloadConfigID, - } - m.detailsByPid[pid] = details - - if _, found := m.detailsByWorkload[workloadConfigID]; !found { - // first instrumentation for this workload - m.detailsByWorkload[workloadConfigID] = map[int]*instrumentationDetails{pid: details} - } else { - m.detailsByWorkload[workloadConfigID][pid] = details - } -} - -func (m *Manager) stopTrackInstrumentation(pid int) { - details, ok := m.detailsByPid[pid] - if !ok { - return - } - workloadConfigID := details.configID - - delete(m.detailsByPid, pid) - delete(m.detailsByWorkload[workloadConfigID], pid) - - if len(m.detailsByWorkload[workloadConfigID]) == 0 { - delete(m.detailsByWorkload, workloadConfigID) - } -} - -func (m *Manager) instrumentationSDKConfig(ctx context.Context, w *workloadUtils.PodWorkload, lang common.ProgrammingLanguage, podKey types.NamespacedName) *odigosv1.SdkConfig { - instrumentationConfig := odigosv1.InstrumentationConfig{} - instrumentationConfigKey := client.ObjectKey{ - Namespace: w.Namespace, - Name: workloadUtils.CalculateWorkloadRuntimeObjectName(w.Name, w.Kind), - } - if err := m.client.Get(ctx, instrumentationConfigKey, &instrumentationConfig); err != nil { - // this can be valid when the instrumentation config is deleted and current pods will go down soon - m.logger.Error(err, "failed to get initial instrumentation config for instrumented pod", "pod", podKey.Name, "namespace", podKey.Namespace) - return nil - } - for _, config := range instrumentationConfig.Spec.SdkConfigs { - if config.Language == lang { - return &config - } - } - return nil -} - -func (m *Manager) applyInstrumentationConfigurationForSDK(ctx context.Context, podWorkload workload.PodWorkload, sdkConfig *odigosv1.SdkConfig) error { - var err error - - configID := workloadConfigID{ - podWorkload: podWorkload, - lang: sdkConfig.Language, - } - - workloadInstrumentations, ok := m.detailsByWorkload[configID] - if !ok { - return nil - } - - for _, instDetails := range workloadInstrumentations { - m.logger.Info("applying configuration to instrumentation", "podWorkload", podWorkload, "pod", instDetails.pod, "language", sdkConfig.Language) - applyErr := instDetails.inst.ApplyConfig(ctx, sdkConfig) - err = errors.Join(err, applyErr) - } - return err -} - -func (m *Manager) updateInstrumentationInstanceStatus(ctx context.Context, pod *corev1.Pod, containerName string, w *workloadUtils.PodWorkload, pid int, health InstrumentationHealth, reason InstrumentationStatusReason, msg string) error { - instrumentedAppName := workloadUtils.CalculateWorkloadRuntimeObjectName(w.Name, w.Kind) - healthy := bool(health) - return instance.UpdateInstrumentationInstanceStatus(ctx, pod, containerName, m.client, instrumentedAppName, pid, m.client.Scheme(), - instance.WithHealthy(&healthy, string(reason), &msg), - ) -} - -func (m *Manager) podFromProcEvent(ctx context.Context, event detector.ProcessEvent) (*corev1.Pod, error) { - eventEnvs := event.ExecDetails.Environments - - podName, ok := eventEnvs[consts.OdigosEnvVarPodName] - if !ok { - return nil, errPodNameNotReported - } - - podNamespace, ok := eventEnvs[consts.OdigosEnvVarNamespace] - if !ok { - return nil, errPodNameSpaceNotReported - } - - pod := corev1.Pod{} - err := m.client.Get(ctx, client.ObjectKey{Namespace: podNamespace, Name: podName}, &pod) - if err != nil { - return nil, fmt.Errorf("error fetching pod object: %w", err) - } - - return &pod, nil -} - -func containerNameFromProcEvent(event detector.ProcessEvent) (string, bool) { - containerName, ok := event.ExecDetails.Environments[consts.OdigosEnvVarContainerName] - return containerName, ok -} diff --git a/odiglet/pkg/ebpf/reporter.go b/odiglet/pkg/ebpf/reporter.go new file mode 100644 index 000000000..ec52647e6 --- /dev/null +++ b/odiglet/pkg/ebpf/reporter.go @@ -0,0 +1,123 @@ +package ebpf + +import ( + "context" + "fmt" + + odigosv1 "github.com/odigos-io/odigos/api/odigos/v1alpha1" + "github.com/odigos-io/odigos/common" + "github.com/odigos-io/odigos/instrumentation" + "github.com/odigos-io/odigos/k8sutils/pkg/consts" + instance "github.com/odigos-io/odigos/k8sutils/pkg/instrumentation_instance" + "github.com/odigos-io/odigos/k8sutils/pkg/workload" + corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +type K8sProcessGroup struct { + pod *corev1.Pod + containerName string + pw *workload.PodWorkload +} + +func (kd K8sProcessGroup) String() string { + return fmt.Sprintf("Pod: %s.%s, Container: %s, Workload: %s", + kd.pod.Name, kd.pod.Namespace, + kd.containerName, + workload.CalculateWorkloadRuntimeObjectName(kd.pw.Name, kd.pw.Kind), + ) +} + +var _ instrumentation.ProcessGroup = K8sProcessGroup{} + +type k8sReporter struct { + client client.Client +} + +type K8sConfigGroup struct { + Pw workload.PodWorkload + Lang common.ProgrammingLanguage +} + +var _ instrumentation.Reporter[K8sProcessGroup] = &k8sReporter{} + +type errRequiredEnvVarNotFound struct { + envVarName string +} + +func (e *errRequiredEnvVarNotFound) Error() string { + return fmt.Sprintf("required environment variable not found: %s", e.envVarName) +} + +var _ error = &errRequiredEnvVarNotFound{} + +var ( + errContainerNameNotReported = &errRequiredEnvVarNotFound{envVarName: consts.OdigosEnvVarContainerName} + errPodNameNotReported = &errRequiredEnvVarNotFound{envVarName: consts.OdigosEnvVarPodName} + errPodNameSpaceNotReported = &errRequiredEnvVarNotFound{envVarName: consts.OdigosEnvVarNamespace} +) + +type InstrumentationStatusReason string + +const ( + FailedToLoad InstrumentationStatusReason = "FailedToLoad" + FailedToInitialize InstrumentationStatusReason = "FailedToInitialize" + LoadedSuccessfully InstrumentationStatusReason = "LoadedSuccessfully" + FailedToRun InstrumentationStatusReason = "FailedToRun" +) + +type InstrumentationHealth bool + +const ( + InstrumentationHealthy InstrumentationHealth = true + InstrumentationUnhealthy InstrumentationHealth = false +) + +func (r *k8sReporter) OnInit(ctx context.Context, pid int, err error, e K8sProcessGroup) error { + if err == nil { + // currently we don't report on successful initialization + return nil + } + + return r.updateInstrumentationInstanceStatus(ctx, e, pid, InstrumentationUnhealthy, FailedToInitialize, err.Error()) +} + +func (r *k8sReporter) OnLoad(ctx context.Context, pid int, err error, e K8sProcessGroup) error { + if err != nil { + return r.updateInstrumentationInstanceStatus(ctx, e, pid, InstrumentationUnhealthy, FailedToLoad, err.Error()) + } + + msg := fmt.Sprintf("Successfully loaded eBPF probes to pod: %s container: %s", e.pod.Name, e.containerName) + return r.updateInstrumentationInstanceStatus(ctx, e, pid, InstrumentationHealthy, LoadedSuccessfully, msg) +} + +func (r *k8sReporter) OnRun(ctx context.Context, pid int, err error, e K8sProcessGroup) error { + if err == nil { + // finished running successfully + return nil + } + + return r.updateInstrumentationInstanceStatus(ctx, e, pid, InstrumentationUnhealthy, FailedToRun, err.Error()) +} + +func (r *k8sReporter) OnExit(ctx context.Context, pid int, e K8sProcessGroup) error { + if err := r.client.Delete(ctx, &odigosv1.InstrumentationInstance{ + ObjectMeta: metav1.ObjectMeta{ + Name: instance.InstrumentationInstanceName(e.pod.Name, pid), + Namespace: e.pod.Namespace, + }, + }); err != nil && !apierrors.IsNotFound(err) { + return fmt.Errorf("error deleting instrumentation instance for pod %s pid %d: %w", e.pod.Name, pid, err) + } + return nil +} + +func (r *k8sReporter) updateInstrumentationInstanceStatus(ctx context.Context, ke K8sProcessGroup, pid int, health InstrumentationHealth, reason InstrumentationStatusReason, msg string) error { + instrumentedAppName := workload.CalculateWorkloadRuntimeObjectName(ke.pw.Name, ke.pw.Kind) + healthy := bool(health) + return instance.UpdateInstrumentationInstanceStatus(ctx, ke.pod, ke.containerName, r.client, instrumentedAppName, pid, r.client.Scheme(), + instance.WithHealthy(&healthy, string(reason), &msg), + ) +} diff --git a/odiglet/pkg/ebpf/resolvers.go b/odiglet/pkg/ebpf/resolvers.go new file mode 100644 index 000000000..efb654f9e --- /dev/null +++ b/odiglet/pkg/ebpf/resolvers.go @@ -0,0 +1,79 @@ +package ebpf + +import ( + "context" + "fmt" + + "github.com/odigos-io/odigos/instrumentation" + "github.com/odigos-io/odigos/instrumentation/detector" + "github.com/odigos-io/odigos/k8sutils/pkg/consts" + "github.com/odigos-io/odigos/k8sutils/pkg/workload" + corev1 "k8s.io/api/core/v1" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +type k8sDetailsResolver struct { + client client.Client +} + +func (dr *k8sDetailsResolver) Resolve(ctx context.Context, event detector.ProcessEvent) (K8sProcessGroup, error) { + pod, err := dr.podFromProcEvent(ctx, event) + if err != nil { + return K8sProcessGroup{}, err + } + + containerName, found := containerNameFromProcEvent(event) + if !found { + return K8sProcessGroup{}, errContainerNameNotReported + } + + podWorkload, err := workload.PodWorkloadObjectOrError(ctx, pod) + if err != nil { + return K8sProcessGroup{}, fmt.Errorf("failed to find workload object from pod manifest owners references: %w", err) + } + + return K8sProcessGroup{ + pod: pod, + containerName: containerName, + pw: podWorkload, + }, nil +} + +func (dr *k8sDetailsResolver) podFromProcEvent(ctx context.Context, e detector.ProcessEvent) (*corev1.Pod, error) { + eventEnvs := e.ExecDetails.Environments + + podName, ok := eventEnvs[consts.OdigosEnvVarPodName] + if !ok { + return nil, errPodNameNotReported + } + + podNamespace, ok := eventEnvs[consts.OdigosEnvVarNamespace] + if !ok { + return nil, errPodNameSpaceNotReported + } + + pod := corev1.Pod{} + err := dr.client.Get(ctx, client.ObjectKey{Namespace: podNamespace, Name: podName}, &pod) + if err != nil { + return nil, fmt.Errorf("error fetching pod object: %w", err) + } + + return &pod, nil +} + +func containerNameFromProcEvent(event detector.ProcessEvent) (string, bool) { + containerName, ok := event.ExecDetails.Environments[consts.OdigosEnvVarContainerName] + return containerName, ok +} + +type k8sConfigGroupResolver struct{} + +func (cr *k8sConfigGroupResolver) Resolve(ctx context.Context, d K8sProcessGroup, dist instrumentation.OtelDistribution) (K8sConfigGroup, error) { + if d.pw == nil { + return K8sConfigGroup{}, fmt.Errorf("podWorkload is not provided, cannot resolve config group") + } + return K8sConfigGroup{ + Pw: *d.pw, + Lang: dist.Language, + }, nil +} diff --git a/odiglet/pkg/ebpf/sdks/go.go b/odiglet/pkg/ebpf/sdks/go.go index e22a576c7..72b0aa0a1 100644 --- a/odiglet/pkg/ebpf/sdks/go.go +++ b/odiglet/pkg/ebpf/sdks/go.go @@ -6,6 +6,7 @@ import ( odigosv1 "github.com/odigos-io/odigos/api/odigos/v1alpha1" "github.com/odigos-io/odigos/common" + "github.com/odigos-io/odigos/instrumentation" "github.com/odigos-io/odigos/odiglet/pkg/ebpf" "github.com/odigos-io/odigos/odiglet/pkg/env" @@ -26,11 +27,11 @@ var _ auto.ConfigProvider = (*ebpf.ConfigProvider[auto.InstrumentationConfig])(n type GoInstrumentationFactory struct { } -func NewGoInstrumentationFactory() ebpf.Factory { +func NewGoInstrumentationFactory() instrumentation.Factory { return &GoInstrumentationFactory{} } -func (g *GoInstrumentationFactory) CreateInstrumentation(ctx context.Context, pid int, settings ebpf.Settings) (ebpf.Instrumentation, error) { +func (g *GoInstrumentationFactory) CreateInstrumentation(ctx context.Context, pid int, settings instrumentation.Settings) (instrumentation.Instrumentation, error) { defaultExporter, err := otlptracegrpc.New( ctx, otlptracegrpc.WithInsecure(), @@ -40,7 +41,12 @@ func (g *GoInstrumentationFactory) CreateInstrumentation(ctx context.Context, pi return nil, fmt.Errorf("failed to create exporter: %w", err) } - cp := ebpf.NewConfigProvider(convertToGoInstrumentationConfig(settings.InitialConfig)) + initialConfig, err := convertToGoInstrumentationConfig(settings.InitialConfig) + if err != nil { + return nil, fmt.Errorf("invalid initial config type, expected *odigosv1.SdkConfig, got %T", settings.InitialConfig) + } + + cp := ebpf.NewConfigProvider(initialConfig) inst, err := auto.NewInstrumentation( ctx, @@ -72,18 +78,27 @@ func (g *GoOtelEbpfSdk) Close(_ context.Context) error { return g.inst.Close() } -func (g *GoOtelEbpfSdk) ApplyConfig(ctx context.Context, sdkConfig *odigosv1.SdkConfig) error { - return g.cp.SendConfig(ctx, convertToGoInstrumentationConfig(sdkConfig)) +func (g *GoOtelEbpfSdk) ApplyConfig(ctx context.Context, sdkConfig instrumentation.Config) error { + updatedConfig, err := convertToGoInstrumentationConfig(sdkConfig) + if err != nil { + return err + } + + return g.cp.SendConfig(ctx, updatedConfig) } -func convertToGoInstrumentationConfig(sdkConfig *odigosv1.SdkConfig) auto.InstrumentationConfig { +func convertToGoInstrumentationConfig(sdkConfig instrumentation.Config) (auto.InstrumentationConfig, error) { + initialConfig, ok := sdkConfig.(*odigosv1.SdkConfig) + if !ok { + return auto.InstrumentationConfig{}, fmt.Errorf("invalid initial config type, expected *odigosv1.SdkConfig, got %T", sdkConfig) + } ic := auto.InstrumentationConfig{} if sdkConfig == nil { log.Logger.V(0).Info("No SDK config provided for Go instrumentation, using default") - return ic + return ic, nil } ic.InstrumentationLibraryConfigs = make(map[auto.InstrumentationLibraryID]auto.InstrumentationLibrary) - for _, ilc := range sdkConfig.InstrumentationLibraryConfigs { + for _, ilc := range initialConfig.InstrumentationLibraryConfigs { libID := auto.InstrumentationLibraryID{ InstrumentedPkg: ilc.InstrumentationLibraryId.InstrumentationLibraryName, SpanKind: common.SpanKindOdigosToOtel(ilc.InstrumentationLibraryId.SpanKind), @@ -99,5 +114,5 @@ func convertToGoInstrumentationConfig(sdkConfig *odigosv1.SdkConfig) auto.Instru // TODO: take sampling config from the CR ic.Sampler = auto.DefaultSampler() - return ic + return ic, nil } diff --git a/odiglet/pkg/ebpf/settings_getter.go b/odiglet/pkg/ebpf/settings_getter.go new file mode 100644 index 000000000..40c420006 --- /dev/null +++ b/odiglet/pkg/ebpf/settings_getter.go @@ -0,0 +1,54 @@ +package ebpf + +import ( + "context" + "fmt" + + odigosv1 "github.com/odigos-io/odigos/api/odigos/v1alpha1" + "github.com/odigos-io/odigos/instrumentation" + workload "github.com/odigos-io/odigos/k8sutils/pkg/workload" + "github.com/odigos-io/odigos/odiglet/pkg/kube/utils" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +type k8sSettingsGetter struct { + client client.Client +} + +var _ instrumentation.SettingsGetter[K8sProcessGroup] = &k8sSettingsGetter{} + +func (ksg *k8sSettingsGetter) Settings(ctx context.Context, kd K8sProcessGroup, dist instrumentation.OtelDistribution) (instrumentation.Settings, error) { + sdkConfig, serviceName, err := ksg.instrumentationSDKConfig(ctx, kd, dist) + if err != nil { + return instrumentation.Settings{}, err + } + + OtelServiceName := serviceName + if serviceName == "" { + OtelServiceName = kd.pw.Name + } + + return instrumentation.Settings{ + ServiceName: OtelServiceName, + ResourceAttributes: utils.GetResourceAttributes(kd.pw, kd.pod.Name), + InitialConfig: sdkConfig, + }, nil +} + +func (ksg *k8sSettingsGetter) instrumentationSDKConfig(ctx context.Context, kd K8sProcessGroup, dist instrumentation.OtelDistribution) (*odigosv1.SdkConfig, string, error) { + instrumentationConfig := odigosv1.InstrumentationConfig{} + instrumentationConfigKey := client.ObjectKey{ + Namespace: kd.pw.Namespace, + Name: workload.CalculateWorkloadRuntimeObjectName(kd.pw.Name, kd.pw.Kind), + } + if err := ksg.client.Get(ctx, instrumentationConfigKey, &instrumentationConfig); err != nil { + // this can be valid when the instrumentation config is deleted and current pods will go down soon + return nil, "", err + } + for _, config := range instrumentationConfig.Spec.SdkConfigs { + if config.Language == dist.Language { + return &config, instrumentationConfig.Spec.ServiceName, nil + } + } + return nil, "", fmt.Errorf("no sdk config found for language %s", dist.Language) +} diff --git a/odiglet/pkg/kube/instrumentation_ebpf/instrumentationconfig.go b/odiglet/pkg/kube/instrumentation_ebpf/instrumentationconfig.go index e067d9f2c..ba900f630 100644 --- a/odiglet/pkg/kube/instrumentation_ebpf/instrumentationconfig.go +++ b/odiglet/pkg/kube/instrumentation_ebpf/instrumentationconfig.go @@ -5,6 +5,7 @@ import ( "errors" "time" + "github.com/odigos-io/odigos/instrumentation" odigosv1 "github.com/odigos-io/odigos/api/odigos/v1alpha1" "github.com/odigos-io/odigos/k8sutils/pkg/workload" "github.com/odigos-io/odigos/odiglet/pkg/ebpf" @@ -18,7 +19,7 @@ type InstrumentationConfigReconciler struct { client.Client Scheme *runtime.Scheme Directors ebpf.DirectorsMap - ConfigUpdates chan<- ebpf.ConfigUpdate + ConfigUpdates chan<- instrumentation.ConfigUpdate[ebpf.K8sConfigGroup] } var ( @@ -62,15 +63,24 @@ func (i *InstrumentationConfigReconciler) Reconcile(ctx context.Context, req ctr } if i.ConfigUpdates != nil { + if len(instrumentationConfig.Spec.SdkConfigs) == 0 { + return ctrl.Result{}, nil + } + // send a config update request for all the instrumentation which are part of the workload. // if the config request is sent, the configuration updates will occur asynchronously. ctx, cancel := context.WithTimeout(ctx, configUpdateTimeout) defer cancel() + configUpdate := instrumentation.ConfigUpdate[ebpf.K8sConfigGroup]{} + for _, sdkConfig := range instrumentationConfig.Spec.SdkConfigs { + cg := ebpf.K8sConfigGroup{Pw: podWorkload, Lang: sdkConfig.Language} + currentConfig := sdkConfig + configUpdate[cg] = ¤tConfig + } + select { - case i.ConfigUpdates <- ebpf.ConfigUpdate{ - PodWorkload: podWorkload, - Config: instrumentationConfig}: + case i.ConfigUpdates <-configUpdate: return ctrl.Result{}, nil case <-ctx.Done(): if ctx.Err() == context.DeadlineExceeded { diff --git a/odiglet/pkg/kube/instrumentation_ebpf/manager.go b/odiglet/pkg/kube/instrumentation_ebpf/manager.go index 57c95f16b..05467692c 100644 --- a/odiglet/pkg/kube/instrumentation_ebpf/manager.go +++ b/odiglet/pkg/kube/instrumentation_ebpf/manager.go @@ -3,6 +3,7 @@ package instrumentation_ebpf import ( "sigs.k8s.io/controller-runtime/pkg/predicate" + "github.com/odigos-io/odigos/instrumentation" odigosv1 "github.com/odigos-io/odigos/api/odigos/v1alpha1" odigospredicate "github.com/odigos-io/odigos/k8sutils/pkg/predicate" "github.com/odigos-io/odigos/odiglet/pkg/ebpf" @@ -12,7 +13,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/builder" ) -func SetupWithManager(mgr ctrl.Manager, ebpfDirectors ebpf.DirectorsMap, configUpdates chan<- ebpf.ConfigUpdate) error { +func SetupWithManager(mgr ctrl.Manager, ebpfDirectors ebpf.DirectorsMap, configUpdates chan<- instrumentation.ConfigUpdate[ebpf.K8sConfigGroup]) error { log.Logger.V(0).Info("Starting reconcileres for ebpf instrumentation") var err error diff --git a/odiglet/pkg/kube/manager.go b/odiglet/pkg/kube/manager.go index 530a48c2a..3b1b911a9 100644 --- a/odiglet/pkg/kube/manager.go +++ b/odiglet/pkg/kube/manager.go @@ -2,6 +2,7 @@ package kube import ( "github.com/odigos-io/odigos/common/consts" + "github.com/odigos-io/odigos/instrumentation" "k8s.io/apimachinery/pkg/labels" "github.com/odigos-io/odigos/odiglet/pkg/ebpf" @@ -59,7 +60,7 @@ func CreateManager() (ctrl.Manager, error) { }) } -func SetupWithManager(mgr ctrl.Manager, ebpfDirectors ebpf.DirectorsMap, clientset *kubernetes.Clientset, configUpdates chan<- ebpf.ConfigUpdate) error { +func SetupWithManager(mgr ctrl.Manager, ebpfDirectors ebpf.DirectorsMap, clientset *kubernetes.Clientset, configUpdates chan<- instrumentation.ConfigUpdate[ebpf.K8sConfigGroup]) error { err := runtime_details.SetupWithManager(mgr, clientset) if err != nil { return err diff --git a/procdiscovery/go.mod b/procdiscovery/go.mod index 513daf78f..09d39486a 100644 --- a/procdiscovery/go.mod +++ b/procdiscovery/go.mod @@ -4,7 +4,7 @@ go 1.23.0 require ( github.com/hashicorp/go-version v1.7.0 - github.com/odigos-io/odigos/common v1.0.48 + github.com/odigos-io/odigos/common v0.0.0 ) require ( diff --git a/scheduler/controllers/nodecollectorsgroup/common.go b/scheduler/controllers/nodecollectorsgroup/common.go index 28156ce9f..18a054fb6 100644 --- a/scheduler/controllers/nodecollectorsgroup/common.go +++ b/scheduler/controllers/nodecollectorsgroup/common.go @@ -34,9 +34,14 @@ const ( // allowing the memory limit to be slightly above the memory request can help in reducing the chances of OOMs in edge cases. // instead of having the process killed, it can use extra memory available on the node without allocating it preemptively. memoryLimitAboveRequestFactor = 2.0 + + // the default CPU request in millicores + defaultRequestCPUm = 250 + // the default CPU limit in millicores + defaultLimitCPUm = 500 ) -func getMemorySettings(odigosConfig common.OdigosConfiguration) odigosv1.CollectorsGroupResourcesSettings { +func getResourceSettings(odigosConfig common.OdigosConfiguration) odigosv1.CollectorsGroupResourcesSettings { // memory request is expensive on daemonsets since it will consume this memory // on each node in the cluster. setting to 256, but allowing memory to spike higher // to consume more available memory on the node. @@ -78,12 +83,23 @@ func getMemorySettings(odigosConfig common.OdigosConfiguration) odigosv1.Collect gomemlimitMiB = nodeCollectorConfig.GoMemLimitMib } + cpuRequestm := defaultRequestCPUm + if nodeCollectorConfig != nil && nodeCollectorConfig.RequestCPUm > 0 { + cpuRequestm = nodeCollectorConfig.RequestCPUm + } + cpuLimitm := defaultLimitCPUm + if nodeCollectorConfig != nil && nodeCollectorConfig.LimitCPUm > 0 { + cpuLimitm = nodeCollectorConfig.LimitCPUm + } + return odigosv1.CollectorsGroupResourcesSettings{ MemoryRequestMiB: memoryRequestMiB, MemoryLimitMiB: memoryLimitMiB, MemoryLimiterLimitMiB: memoryLimiterLimitMiB, MemoryLimiterSpikeLimitMiB: memoryLimiterSpikeLimitMiB, GomemlimitMiB: gomemlimitMiB, + CpuRequestMillicores: cpuRequestm, + CpuLimitMillicores: cpuLimitm, } } @@ -106,7 +122,7 @@ func newNodeCollectorGroup(odigosConfig common.OdigosConfiguration) *odigosv1.Co Spec: odigosv1.CollectorsGroupSpec{ Role: odigosv1.CollectorsGroupRoleNodeCollector, CollectorOwnMetricsPort: ownMetricsPort, - ResourcesSettings: getMemorySettings(odigosConfig), + ResourcesSettings: getResourceSettings(odigosConfig), }, } } diff --git a/scheduler/go.mod b/scheduler/go.mod index 24b0507cb..f1c4c8f4e 100644 --- a/scheduler/go.mod +++ b/scheduler/go.mod @@ -9,10 +9,10 @@ require ( github.com/odigos-io/odigos/k8sutils v0.0.0 github.com/odigos-io/opentelemetry-zap-bridge v0.0.5 github.com/onsi/ginkgo v1.16.5 - github.com/onsi/gomega v1.36.0 - k8s.io/api v0.31.3 - k8s.io/apimachinery v0.31.3 - k8s.io/client-go v0.31.3 + github.com/onsi/gomega v1.36.1 + k8s.io/api v0.32.0 + k8s.io/apimachinery v0.32.0 + k8s.io/client-go v0.32.0 sigs.k8s.io/controller-runtime v0.19.3 ) @@ -29,12 +29,11 @@ require ( github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect - github.com/go-openapi/jsonpointer v0.19.6 // indirect + github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect - github.com/go-openapi/swag v0.22.4 // indirect + github.com/go-openapi/swag v0.23.0 // indirect github.com/goccy/go-yaml v1.11.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/google/gnostic-models v0.6.8 // indirect github.com/google/go-cmp v0.6.0 // indirect @@ -42,7 +41,6 @@ require ( github.com/google/uuid v1.6.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect github.com/hashicorp/go-version v1.7.0 // indirect - github.com/imdario/mergo v0.3.12 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/mailru/easyjson v0.7.7 // indirect @@ -68,27 +66,27 @@ require ( go.uber.org/zap v1.26.0 // indirect golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect golang.org/x/net v0.30.0 // indirect - golang.org/x/oauth2 v0.21.0 // indirect + golang.org/x/oauth2 v0.23.0 // indirect golang.org/x/sys v0.26.0 // indirect golang.org/x/term v0.25.0 // indirect golang.org/x/text v0.19.0 // indirect - golang.org/x/time v0.3.0 // indirect + golang.org/x/time v0.7.0 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect google.golang.org/grpc v1.65.0 // indirect google.golang.org/protobuf v1.35.1 // indirect + gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/apiextensions-apiserver v0.31.0 // indirect k8s.io/klog/v2 v2.130.1 // indirect - k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect - k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 // indirect - sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect + k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f // indirect + k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect + sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.4.2 // indirect sigs.k8s.io/yaml v1.4.0 // indirect ) diff --git a/scheduler/go.sum b/scheduler/go.sum index 59200f5eb..4781eb035 100644 --- a/scheduler/go.sum +++ b/scheduler/go.sum @@ -32,13 +32,14 @@ github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= -github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= +github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= +github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= -github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU= -github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= +github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= @@ -53,8 +54,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.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= @@ -75,8 +74,8 @@ github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/pprof v0.0.0-20240827171923-fa2c70bbbfe5 h1:5iH8iuqE5apketRbSFBy+X1V0o+l+8NF1avt4HWl7cA= -github.com/google/pprof v0.0.0-20240827171923-fa2c70bbbfe5/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= +github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo= +github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0= @@ -84,8 +83,6 @@ github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737 github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= -github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= @@ -123,12 +120,12 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= -github.com/onsi/ginkgo/v2 v2.20.1 h1:YlVIbqct+ZmnEph770q9Q7NVAz4wwIiVNahee6JyUzo= -github.com/onsi/ginkgo/v2 v2.20.1/go.mod h1:lG9ey2Z29hR41WMVthyJBGUBcBhGOtoPF2VFMvBXFCI= +github.com/onsi/ginkgo/v2 v2.21.0 h1:7rg/4f3rB88pb5obDgNZrNHrQ4e6WpjonchcpuBRnZM= +github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.36.0 h1:Pb12RlruUtj4XUuPUqeEWc6j5DkVVVA49Uf6YLfC95Y= -github.com/onsi/gomega v1.36.0/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog= +github.com/onsi/gomega v1.36.1 h1:bJDPBO7ibjxcbHMgSCoo4Yj18UWbKDlLwX1x9sybDcw= +github.com/onsi/gomega v1.36.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -195,8 +192,8 @@ golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= -golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= -golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= +golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -220,15 +217,15 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= -golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= -golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ= +golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= -golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= +golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ= +golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -263,32 +260,29 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkep gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -k8s.io/api v0.31.3 h1:umzm5o8lFbdN/hIXbrK9oRpOproJO62CV1zqxXrLgk8= -k8s.io/api v0.31.3/go.mod h1:UJrkIp9pnMOI9K2nlL6vwpxRzzEX5sWgn8kGQe92kCE= +k8s.io/api v0.32.0 h1:OL9JpbvAU5ny9ga2fb24X8H6xQlVp+aJMFlgtQjR9CE= +k8s.io/api v0.32.0/go.mod h1:4LEwHZEf6Q/cG96F3dqR965sYOfmPM7rq81BLgsE0p0= k8s.io/apiextensions-apiserver v0.31.0 h1:fZgCVhGwsclj3qCw1buVXCV6khjRzKC5eCFt24kyLSk= k8s.io/apiextensions-apiserver v0.31.0/go.mod h1:b9aMDEYaEe5sdK+1T0KU78ApR/5ZVp4i56VacZYEHxk= -k8s.io/apimachinery v0.31.3 h1:6l0WhcYgasZ/wk9ktLq5vLaoXJJr5ts6lkaQzgeYPq4= -k8s.io/apimachinery v0.31.3/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= -k8s.io/client-go v0.31.3 h1:CAlZuM+PH2cm+86LOBemaJI/lQ5linJ6UFxKX/SoG+4= -k8s.io/client-go v0.31.3/go.mod h1:2CgjPUTpv3fE5dNygAr2NcM8nhHzXvxB8KL5gYc3kJs= +k8s.io/apimachinery v0.32.0 h1:cFSE7N3rmEEtv4ei5X6DaJPHHX0C+upp+v5lVPiEwpg= +k8s.io/apimachinery v0.32.0/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE= +k8s.io/client-go v0.32.0 h1:DimtMcnN/JIKZcrSrstiwvvZvLjG0aSxy8PxN8IChp8= +k8s.io/client-go v0.32.0/go.mod h1:boDWvdM1Drk4NJj/VddSLnx59X3OPgwrOo0vGbtq9+8= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= -k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag= -k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98= -k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A= -k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f h1:GA7//TjRY9yWGy1poLzYYJJ4JRdzg3+O6e8I+e+8T5Y= +k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f/go.mod h1:R/HEjbvWI0qdfb8viZUeVZm0X6IZnxAydC7YU42CMw4= +k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6JSWYFzOFnYeS6Ro= +k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= sigs.k8s.io/controller-runtime v0.19.3 h1:XO2GvC9OPftRst6xWCpTgBZO04S2cbp0Qqkj8bX1sPw= sigs.k8s.io/controller-runtime v0.19.3/go.mod h1:j4j87DqtsThvwTv5/Tc5NFRyyF/RF0ip4+62tbTSIUM= -sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= -sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= -sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= -sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= +sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8= +sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo= +sigs.k8s.io/structured-merge-diff/v4 v4.4.2 h1:MdmvkGuXi/8io6ixD5wud3vOLwc1rj0aNqRlpuvjmwA= +sigs.k8s.io/structured-merge-diff/v4 v4.4.2/go.mod h1:N8f93tFZh9U6vpxwRArLiikrE5/2tiu1w1AGfACIGE4= sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/tests/common/assert/pipeline-ready.yaml b/tests/common/assert/pipeline-ready.yaml index 2c52b1386..6c023c690 100644 --- a/tests/common/assert/pipeline-ready.yaml +++ b/tests/common/assert/pipeline-ready.yaml @@ -55,12 +55,20 @@ spec: fieldPath: metadata.name - name: GOMEMLIMIT (value != null): true + - name: GOMAXPROCS + valueFrom: + resourceFieldRef: + containerName: gateway + divisor: "0" + resource: limits.cpu name: gateway resources: requests: (memory != null): true + (cpu != null): true limits: (memory != null): true + (cpu != null): true volumeMounts: - mountPath: /conf name: collector-conf diff --git a/tests/common/assert_pipeline_pods_ready.sh b/tests/common/assert_pipeline_pods_ready.sh new file mode 100755 index 000000000..43024745e --- /dev/null +++ b/tests/common/assert_pipeline_pods_ready.sh @@ -0,0 +1,45 @@ +#!/bin/bash + +DEFAULT_NAMESPACE="odigos-test" +DEFAULT_TIMEOUT="120s" +CHECK_INTERVAL=5 + +NAMESPACE=${1:-$DEFAULT_NAMESPACE} +TIMEOUT=${2:-$DEFAULT_TIMEOUT} + +# Define expected labels for pods (adjust as needed) +EXPECTED_LABELS=( + "odigos.io/collector-role=NODE_COLLECTOR" # For odigos-data-collection pods + "odigos.io/collector-role=CLUSTER_GATEWAY" # For odigos-gateway pods + "app.kubernetes.io/name=odigos-autoscaler" + "app.kubernetes.io/name=odigos-instrumentor" + "app.kubernetes.io/name=odigos-scheduler" + "app=odigos-ui" +) + +echo "Waiting for all expected pods to be ready in namespace '$NAMESPACE' with timeout of $TIMEOUT..." + +for label in "${EXPECTED_LABELS[@]}"; do + echo "Waiting for pods with label: $label..." + # Wait for pods to exist before using kubectl wait + EXISTS=false + while [[ "$EXISTS" == "false" ]]; do + POD_COUNT=$(kubectl get pods -l "$label" -n "$NAMESPACE" --no-headers 2>/dev/null | wc -l) + if [[ "$POD_COUNT" -gt 0 ]]; then + EXISTS=true + echo "Found $POD_COUNT pod(s) with label '$label'. Proceeding to wait for readiness..." + else + echo "No pods found with label '$label'. Checking again in $CHECK_INTERVAL seconds..." + sleep $CHECK_INTERVAL + fi + done + + # Use `kubectl wait` to check all pods matching the label + kubectl wait --for=condition=Ready pods -l "$label" -n "$NAMESPACE" --timeout="$TIMEOUT" + if [[ $? -ne 0 ]]; then + echo "Pods with label '$label' did not become ready within $TIMEOUT in namespace '$NAMESPACE'" + exit 1 + fi +done + +echo "All expected pods are ready!" diff --git a/tests/e2e/cli-upgrade/chainsaw-test.yaml b/tests/e2e/cli-upgrade/chainsaw-test.yaml index b9907593f..e4171fe75 100644 --- a/tests/e2e/cli-upgrade/chainsaw-test.yaml +++ b/tests/e2e/cli-upgrade/chainsaw-test.yaml @@ -103,10 +103,15 @@ spec: try: - apply: file: ../../common/apply/add-tempo-traces-destination.yaml - - name: Odigos pipeline ready + - name: Odigos pipeline pods ready + # We make sure that the pipeline pods are ready before proceeding with the next steps + # This is intentionally different from pipeline-ready.yaml, which checks for the pipeline CRDs + # When adding a feature related to the pipeline, if we would use the same assert before the upgrade, the test would fail. + # Since the version installed here is latest official one. try: - - assert: - file: ../../common/assert/pipeline-ready.yaml + - script: + content: ../../common/assert_pipeline_pods_ready.sh + timeout: 60s - name: Simple-demo instrumented after destination added try: - assert: diff --git a/tests/e2e/workload-lifecycle/03-assert-action-created.yaml b/tests/e2e/workload-lifecycle/03-assert-action-created.yaml index 8729b705a..74e66e758 100644 --- a/tests/e2e/workload-lifecycle/03-assert-action-created.yaml +++ b/tests/e2e/workload-lifecycle/03-assert-action-created.yaml @@ -63,6 +63,12 @@ spec: fieldPath: metadata.name - name: GOMEMLIMIT (value != null): true + - name: GOMAXPROCS + valueFrom: + resourceFieldRef: + containerName: gateway + divisor: "0" + resource: limits.cpu name: gateway resources: requests: