Repository: open-telemetry/opentelemetry-operator
Pull request #3960 (2025-04-30 07:51:12)

[Chore] Update Golang test app to generate telemetry data
**Description:** <Describe what has changed.>
Update the Golang test app to generate telemetry data. 



Patch:
diff --git a/.chloggen/fix_ta-cmdline-values.yaml b/.chloggen/fix_ta-cmdline-values.yaml
new file mode 100755
index 00000000..9734ece9
--- /dev/null
+++ b/.chloggen/fix_ta-cmdline-values.yaml
@@ -0,0 +1,16 @@
+# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
+change_type: bug_fix
+
+# The name of the component, or a single word describing the area of concern, (e.g. collector, target allocator, auto-instrumentation, opamp, github action)
+component: target allocator
+
+# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
+note: Fix config loading priority
+
+# One or more tracking issues related to the change
+issues: [3928]
+
+# (Optional) One or more lines of additional information to render under the primary note.
+# These lines will be padded with 2 spaces and then inserted directly into the document.
+# Use pipe (|) for multiline entries.
+subtext:
\ No newline at end of file
diff --git a/cmd/otel-allocator/internal/config/config.go b/cmd/otel-allocator/internal/config/config.go
index f118fc33..bc51a1d6 100644
--- a/cmd/otel-allocator/internal/config/config.go
+++ b/cmd/otel-allocator/internal/config/config.go
@@ -12,6 +12,7 @@ import (
 	"log/slog"
 	"math"
 	"os"
+	"path/filepath"
 	"reflect"
 	"time"
 
@@ -26,12 +27,15 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/client-go/rest"
 	"k8s.io/client-go/tools/clientcmd"
+	"k8s.io/client-go/util/homedir"
 	"k8s.io/klog/v2"
 	ctrl "sigs.k8s.io/controller-runtime"
 	"sigs.k8s.io/controller-runtime/pkg/log/zap"
 )
 
 const (
+	DefaultListenAddr                                  = ":8080"
+	DefaultHttpsListenAddr                             = ":8443"
 	DefaultResyncTime                                  = 5 * time.Minute
 	DefaultConfigFilePath               string         = "/conf/targetallocator.yaml"
 	DefaultCRScrapeInterval             model.Duration = model.Duration(time.Second * 30)
@@ -40,6 +44,10 @@ const (
 	DefaultCollectorNotReadyGracePeriod                = 0 * time.Second
 )
 
+var (
+	DefaultKubeConfigFilePath string = filepath.Join(homedir.HomeDir(), ".kube", "config")
+)
+
 // By default, scrape protocols include PrometheusText1_0_0, which only Prometheus >=3.0 supports.
 // Manually exclude this protocol until several versions of the Otel Collector support it.
 var DefaultScrapeProtocols = []promconfig.ScrapeProtocol{
@@ -227,9 +235,10 @@ func LoadFromCLI(target *Config, flagSet *pflag.FlagSet) error {
 	klog.SetLogger(target.RootLogger)
 	ctrl.SetLogger(target.RootLogger)
 
-	target.KubeConfigFilePath, err = getKubeConfigFilePath(flagSet)
-	if err != nil {
-		return err
+	if kubeConfigFilePath, changed, flagErr := getKubeConfigFilePath(flagSet); flagErr != nil {
+		return flagErr
+	} else if changed {
+		target.KubeConfigFilePath = kubeConfigFilePath
 	}
 	clusterConfig, err := clientcmd.BuildConfigFromFlags("", target.KubeConfigFilePath)
 	if err != nil {
@@ -245,9 +254,10 @@ func LoadFromCLI(target *Config, flagSet *pflag.FlagSet) error {
 	}
 	target.ClusterConfig = clusterConfig
 
-	target.ListenAddr, err = getListenAddr(flagSet)
-	if err != nil {
-		return err
+	if listenAddr, changed, flagErr := getListenAddr(flagSet); flagErr != nil {
+		return flagErr
+	} else if changed {
+		target.ListenAddr = listenAddr
 	}
 
 	if prometheusCREnabled, changed, flagErr := getPrometheusCREnabled(flagSet); flagErr != nil {
@@ -335,6 +345,11 @@ func unmarshal(cfg *Config, configFile string) error {
 
 func CreateDefaultConfig() Config {
 	return Config{
+		ListenAddr:         DefaultListenAddr,
+		KubeConfigFilePath: DefaultKubeConfigFilePath,
+		HTTPS: HTTPSServerConfig{
+			ListenAddr: DefaultHttpsListenAddr,
+		},
 		AllocationStrategy:         DefaultAllocationStrategy,
 		AllocationFallbackStrategy: "",
 		FilterStrategy:             DefaultFilterStrategy,
@@ -349,11 +364,11 @@ func CreateDefaultConfig() Config {
 	}
 }
 
-func Load() (*Config, error) {
+func Load(args []string) (*Config, error) {
 	var err error
 
 	flagSet := getFlagSet(pflag.ExitOnError)
-	err = flagSet.Parse(os.Args)
+	err = flagSet.Parse(args)
 	if err != nil {
 		return nil, err
 	}
diff --git a/cmd/otel-allocator/internal/config/flags.go b/cmd/otel-allocator/internal/config/flags.go
index 5c812e8f..ae156ff8 100644
--- a/cmd/otel-allocator/internal/config/flags.go
+++ b/cmd/otel-allocator/internal/config/flags.go
@@ -5,10 +5,8 @@ package config
 
 import (
 	"flag"
-	"path/filepath"
 
 	"github.com/spf13/pflag"
-	"k8s.io/client-go/util/homedir"
 	"sigs.k8s.io/controller-runtime/pkg/log/zap"
 )
 
@@ -32,11 +30,11 @@ var zapCmdLineOpts zap.Options
 func getFlagSet(errorHandling pflag.ErrorHandling) *pflag.FlagSet {
 	flagSet := pflag.NewFlagSet(targetAllocatorName, errorHandling)
 	flagSet.String(configFilePathFlagName, DefaultConfigFilePath, "The path to the config file.")
-	flagSet.String(listenAddrFlagName, ":8080", "The address where this service serves.")
+	flagSet.String(listenAddrFlagName, DefaultListenAddr, "The address where this service serves.")
 	flagSet.Bool(prometheusCREnabledFlagName, false, "Enable Prometheus CRs as target sources")
-	flagSet.String(kubeConfigPathFlagName, filepath.Join(homedir.HomeDir(), ".kube", "config"), "absolute path to the KubeconfigPath file")
+	flagSet.String(kubeConfigPathFlagName, DefaultKubeConfigFilePath, "absolute path to the KubeconfigPath file")
 	flagSet.Bool(httpsEnabledFlagName, false, "Enable HTTPS additional server")
-	flagSet.String(listenAddrHttpsFlagName, ":8443", "The address where this service serves over HTTPS.")
+	flagSet.String(listenAddrHttpsFlagName, DefaultHttpsListenAddr, "The address where this service serves over HTTPS.")
 	flagSet.String(httpsCAFilePathFlagName, "", "The path to the HTTPS server TLS CA file.")
 	flagSet.String(httpsTLSCertFilePathFlagName, "", "The path to the HTTPS server TLS certificate file.")
 	flagSet.String(httpsTLSKeyFilePathFlagName, "", "The path to the HTTPS server TLS key file.")
@@ -50,64 +48,54 @@ func getConfigFilePath(flagSet *pflag.FlagSet) (string, error) {
 	return flagSet.GetString(configFilePathFlagName)
 }
 
-func getKubeConfigFilePath(flagSet *pflag.FlagSet) (string, error) {
-	return flagSet.GetString(kubeConfigPathFlagName)
+func getKubeConfigFilePath(flagSet *pflag.FlagSet) (value string, changed bool, err error) {
+	return getFlagValueAndChangedString(flagSet, kubeConfigPathFlagName)
 }
 
-func getListenAddr(flagSet *pflag.FlagSet) (string, error) {
-	return flagSet.GetString(listenAddrFlagName)
+func getListenAddr(flagSet *pflag.FlagSet) (value string, changed bool, err error) {
+	return getFlagValueAndChangedString(flagSet, listenAddrFlagName)
 }
 
 func getPrometheusCREnabled(flagSet *pflag.FlagSet) (value bool, changed bool, err error) {
-	if changed = flagSet.Changed(prometheusCREnabledFlagName); !changed {
-		value, err = false, nil
-		return
-	}
-	value, err = flagSet.GetBool(prometheusCREnabledFlagName)
-	return
+	return getFlagValueAndChangedBool(flagSet, prometheusCREnabledFlagName)
 }
 
 func getHttpsListenAddr(flagSet *pflag.FlagSet) (value string, changed bool, err error) {
-	if changed = flagSet.Changed(listenAddrHttpsFlagName); !changed {
-		value, err = ":8443", nil
-		return
-	}
-	value, err = flagSet.GetString(listenAddrHttpsFlagName)
-	return
+	return getFlagValueAndChangedString(flagSet, listenAddrHttpsFlagName)
 }
 
 func getHttpsEnabled(flagSet *pflag.FlagSet) (value bool, changed bool, err error) {
-	if changed = flagSet.Changed(httpsEnabledFlagName); !changed {
-		value, err = false, nil
-		return
-	}
-	value, err = flagSet.GetBool(httpsEnabledFlagName)
-	return
+	return getFlagValueAndChangedBool(flagSet, httpsEnabledFlagName)
 }
 
 func getHttpsCAFilePath(flagSet *pflag.FlagSet) (value string, changed bool, err error) {
-	if changed = flagSet.Changed(httpsCAFilePathFlagName); !changed {
-		value, err = "", nil
-		return
-	}
-	value, err = flagSet.GetString(httpsCAFilePathFlagName)
-	return
+	return getFlagValueAndChangedString(flagSet, httpsCAFilePathFlagName)
 }
 
 func getHttpsTLSCertFilePath(flagSet *pflag.FlagSet) (value string, changed bool, err error) {
-	if changed = flagSet.Changed(httpsTLSCertFilePathFlagName); !changed {
+	return getFlagValueAndChangedString(flagSet, httpsTLSCertFilePathFlagName)
+}
+
+func getHttpsTLSKeyFilePath(flagSet *pflag.FlagSet) (value string, changed bool, err error) {
+	return getFlagValueAndChangedString(flagSet, httpsTLSKeyFilePathFlagName)
+}
+
+// getFlagValueAndChanged returns the given flag's string value and whether it was changed.
+func getFlagValueAndChangedString(flagSet *pflag.FlagSet, flagName string) (value string, changed bool, err error) {
+	if changed = flagSet.Changed(flagName); !changed {
 		value, err = "", nil
 		return
 	}
-	value, err = flagSet.GetString(httpsTLSCertFilePathFlagName)
+	value, err = flagSet.GetString(flagName)
 	return
 }
 
-func getHttpsTLSKeyFilePath(flagSet *pflag.FlagSet) (value string, changed bool, err error) {
-	if changed = flagSet.Changed(httpsTLSKeyFilePathFlagName); !changed {
-		value, err = "", nil
+// getFlagValueAndChanged returns the given flag's string value and whether it was changed.
+func getFlagValueAndChangedBool(flagSet *pflag.FlagSet, flagName string) (value bool, changed bool, err error) {
+	if changed = flagSet.Changed(flagName); !changed {
+		value, err = false, nil
 		return
 	}
-	value, err = flagSet.GetString(httpsTLSKeyFilePathFlagName)
+	value, err = flagSet.GetBool(flagName)
 	return
 }
diff --git a/cmd/otel-allocator/main.go b/cmd/otel-allocator/main.go
index 1b387585..6035080f 100644
--- a/cmd/otel-allocator/main.go
+++ b/cmd/otel-allocator/main.go
@@ -52,7 +52,7 @@ func main() {
 		interrupts      = make(chan os.Signal, 1)
 		errChan         = make(chan error)
 	)
-	cfg, err := config.Load()
+	cfg, err := config.Load(os.Args)
 	if err != nil {
 		fmt.Printf("Failed to load config: %v", err)
 		os.Exit(1)


Test patch:
diff --git a/cmd/otel-allocator/internal/config/config_test.go b/cmd/otel-allocator/internal/config/config_test.go
index 9df390f4..7593681e 100644
--- a/cmd/otel-allocator/internal/config/config_test.go
+++ b/cmd/otel-allocator/internal/config/config_test.go
@@ -6,6 +6,7 @@ package config
 import (
 	"fmt"
 	"os"
+	"path/filepath"
 	"testing"
 	"time"
 
@@ -20,7 +21,7 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 )
 
-func TestLoad(t *testing.T) {
+func TestLoadFromFile(t *testing.T) {
 	type args struct {
 		file string
 	}
@@ -36,6 +37,8 @@ func TestLoad(t *testing.T) {
 				file: "./testdata/config_test.yaml",
 			},
 			want: Config{
+				ListenAddr:         DefaultListenAddr,
+				KubeConfigFilePath: DefaultKubeConfigFilePath,
 				AllocationStrategy: DefaultAllocationStrategy,
 				CollectorNamespace: "default",
 				CollectorSelector: &metav1.LabelSelector{
@@ -122,6 +125,8 @@ func TestLoad(t *testing.T) {
 				file: "./testdata/pod_service_selector_test.yaml",
 			},
 			want: Config{
+				ListenAddr:         DefaultListenAddr,
+				KubeConfigFilePath: DefaultKubeConfigFilePath,
 				AllocationStrategy: DefaultAllocationStrategy,
 				CollectorNamespace: "default",
 				CollectorSelector: &metav1.LabelSelector{
@@ -148,6 +153,9 @@ func TestLoad(t *testing.T) {
 					ProbeNamespaceSelector:          &metav1.LabelSelector{},
 					ScrapeInterval:                  DefaultCRScrapeInterval,
 				},
+				HTTPS: HTTPSServerConfig{
+					ListenAddr: ":8443",
+				},
 				PromConfig: &promconfig.Config{
 					GlobalConfig: promconfig.GlobalConfig{
 						ScrapeInterval:     model.Duration(60 * time.Second),
@@ -197,6 +205,8 @@ func TestLoad(t *testing.T) {
 				file: "./testdata/pod_service_selector_camelcase_test.yaml",
 			},
 			want: Config{
+				ListenAddr:         DefaultListenAddr,
+				KubeConfigFilePath: DefaultKubeConfigFilePath,
 				AllocationStrategy: DefaultAllocationStrategy,
 				CollectorNamespace: "default",
 				CollectorSelector: &metav1.LabelSelector{
@@ -223,6 +233,9 @@ func TestLoad(t *testing.T) {
 					ProbeNamespaceSelector:          &metav1.LabelSelector{},
 					ScrapeInterval:                  DefaultCRScrapeInterval,
 				},
+				HTTPS: HTTPSServerConfig{
+					ListenAddr: ":8443",
+				},
 				PromConfig: &promconfig.Config{
 					GlobalConfig: promconfig.GlobalConfig{
 						ScrapeInterval:     model.Duration(60 * time.Second),
@@ -272,6 +285,8 @@ func TestLoad(t *testing.T) {
 				file: "./testdata/pod_service_selector_expressions_test.yaml",
 			},
 			want: Config{
+				ListenAddr:         DefaultListenAddr,
+				KubeConfigFilePath: DefaultKubeConfigFilePath,
 				AllocationStrategy: DefaultAllocationStrategy,
 				CollectorNamespace: "default",
 				CollectorSelector: &metav1.LabelSelector{
@@ -322,6 +337,9 @@ func TestLoad(t *testing.T) {
 					ProbeNamespaceSelector:          &metav1.LabelSelector{},
 					ScrapeInterval:                  DefaultCRScrapeInterval,
 				},
+				HTTPS: HTTPSServerConfig{
+					ListenAddr: ":8443",
+				},
 				PromConfig: &promconfig.Config{
 					GlobalConfig: promconfig.GlobalConfig{
 						ScrapeInterval:     model.Duration(60 * time.Second),
@@ -371,6 +389,8 @@ func TestLoad(t *testing.T) {
 				file: "./testdata/pod_service_selector_camelcase_expressions_test.yaml",
 			},
 			want: Config{
+				ListenAddr:         DefaultListenAddr,
+				KubeConfigFilePath: DefaultKubeConfigFilePath,
 				AllocationStrategy: DefaultAllocationStrategy,
 				CollectorNamespace: "default",
 				CollectorSelector: &metav1.LabelSelector{
@@ -421,6 +441,9 @@ func TestLoad(t *testing.T) {
 					ProbeNamespaceSelector:          &metav1.LabelSelector{},
 					ScrapeInterval:                  DefaultCRScrapeInterval,
 				},
+				HTTPS: HTTPSServerConfig{
+					ListenAddr: ":8443",
+				},
 				PromConfig: &promconfig.Config{
 					GlobalConfig: promconfig.GlobalConfig{
 						ScrapeInterval:     model.Duration(60 * time.Second),
@@ -599,3 +622,259 @@ func TestGetAllowDenyLists(t *testing.T) {
 		})
 	}
 }
+
+func TestConfigLoadPriority(t *testing.T) {
+	// Helper function to create a dummy kube config for tests
+	createDummyKubeConfig := func(t *testing.T, dir string) string {
+		kubeConfigPath := filepath.Join(dir, "kube.config")
+		kubeConfigContent := `
+apiVersion: v1
+kind: Config
+clusters:
+- cluster:
+    server: https://example.com
+  name: test-cluster
+contexts:
+- context:
+    cluster: test-cluster
+    user: test-user
+  name: test-context
+current-context: test-context
+users:
+- name: test-user
+  user:
+    token: dummy-token
+`
+		err := os.WriteFile(kubeConfigPath, []byte(kubeConfigContent), 0600)
+		require.NoError(t, err)
+		return kubeConfigPath
+	}
+
+	t.Run("default values when nothing is set", func(t *testing.T) {
+		// Setup: create empty config file and dummy kube config
+		tempDir := t.TempDir()
+		emptyConfigPath := filepath.Join(tempDir, "empty.yaml")
+		err := os.WriteFile(emptyConfigPath, []byte("{}"), 0600)
+		require.NoError(t, err)
+
+		kubeConfigPath := createDummyKubeConfig(t, tempDir)
+
+		// Prepare args for Load function
+		args := []string{
+			"--" + configFilePathFlagName + "=" + emptyConfigPath,
+			"--" + kubeConfigPathFlagName + "=" + kubeConfigPath,
+		}
+
+		// Load config using the full Load function
+		config, err := Load(args)
+		require.NoError(t, err)
+
+		// Assert defaults are used
+		assert.Equal(t, DefaultListenAddr, config.ListenAddr)
+		assert.Equal(t, kubeConfigPath, config.KubeConfigFilePath)
+		assert.Equal(t, DefaultHttpsListenAddr, config.HTTPS.ListenAddr)
+		assert.Equal(t, DefaultAllocationStrategy, config.AllocationStrategy)
+		assert.Equal(t, DefaultFilterStrategy, config.FilterStrategy)
+		assert.False(t, config.PrometheusCR.Enabled)
+		assert.False(t, config.HTTPS.Enabled)
+	})
+
+	t.Run("command-line has priority over config file for boolean values", func(t *testing.T) {
+		// Setup: create config file with values and dummy kube config
+		tempDir := t.TempDir()
+		configContent := `
+prometheus_cr:
+  enabled: false
+https:
+  enabled: false
+`
+		configPath := filepath.Join(tempDir, "config.yaml")
+		err := os.WriteFile(configPath, []byte(configContent), 0600)
+		require.NoError(t, err)
+
+		kubeConfigPath := createDummyKubeConfig(t, tempDir)
+
+		// Prepare args for Load function that override config file
+		args := []string{
+			"--" + configFilePathFlagName + "=" + configPath,
+			"--" + prometheusCREnabledFlagName + "=true",
+			"--" + httpsEnabledFlagName + "=true",
+			"--" + kubeConfigPathFlagName + "=" + kubeConfigPath,
+		}
+
+		// Load config using the full Load function
+		config, err := Load(args)
+		require.NoError(t, err)
+
+		// Assert CLI values override config file
+		assert.True(t, config.PrometheusCR.Enabled, "CLI should override config file for prometheus CR enabled")
+		assert.True(t, config.HTTPS.Enabled, "CLI should override config file for HTTPS enabled")
+	})
+
+	t.Run("command-line has priority over config file for string values", func(t *testing.T) {
+		// Setup: create config file with values and dummy kube config
+		tempDir := t.TempDir()
+		configContent := `
+listen_addr: ":9090"
+https:
+  listen_addr: ":9443"
+  ca_file_path: "/config/ca.pem"
+  tls_cert_file_path: "/config/cert.pem"
+  tls_key_file_path: "/config/key.pem"
+kube_config_file_path: "/config/kube.config"
+`
+		configPath := filepath.Join(tempDir, "config.yaml")
+		err := os.WriteFile(configPath, []byte(configContent), 0600)
+		require.NoError(t, err)
+
+		kubeConfigPath := createDummyKubeConfig(t, tempDir)
+
+		// CLI values different from config file
+		cliListenAddr := ":8888"
+		cliHttpsListenAddr := ":8443"
+		cliCAPath := "/cli/ca.pem"
+		cliCertPath := "/cli/cert.pem"
+		cliKeyPath := "/cli/key.pem"
+
+		// Prepare args for Load function that override config file
+		args := []string{
+			"--" + configFilePathFlagName + "=" + configPath,
+			"--" + listenAddrFlagName + "=" + cliListenAddr,
+			"--" + listenAddrHttpsFlagName + "=" + cliHttpsListenAddr,
+			"--" + httpsCAFilePathFlagName + "=" + cliCAPath,
+			"--" + httpsTLSCertFilePathFlagName + "=" + cliCertPath,
+			"--" + httpsTLSKeyFilePathFlagName + "=" + cliKeyPath,
+			"--" + kubeConfigPathFlagName + "=" + kubeConfigPath,
+		}
+
+		// Load config using the full Load function
+		config, err := Load(args)
+		require.NoError(t, err)
+
+		// Assert CLI values override config file
+		assert.Equal(t, cliListenAddr, config.ListenAddr, "CLI should override config file for listen address")
+		assert.Equal(t, cliHttpsListenAddr, config.HTTPS.ListenAddr, "CLI should override config file for HTTPS listen address")
+		assert.Equal(t, cliCAPath, config.HTTPS.CAFilePath, "CLI should override config file for CA file path")
+		assert.Equal(t, cliCertPath, config.HTTPS.TLSCertFilePath, "CLI should override config file for TLS cert file path")
+		assert.Equal(t, cliKeyPath, config.HTTPS.TLSKeyFilePath, "CLI should override config file for TLS key file path")
+		assert.Equal(t, kubeConfigPath, config.KubeConfigFilePath, "CLI should override config file for kube config path")
+	})
+
+	t.Run("config file overrides defaults when CLI not specified", func(t *testing.T) {
+		// Setup: create config file with values and dummy kube config
+		tempDir := t.TempDir()
+		configListenAddr := ":7070"
+		kubeConfigPath := createDummyKubeConfig(t, tempDir)
+
+		configContent := `
+listen_addr: "` + configListenAddr + `"
+prometheus_cr:
+  enabled: true
+https:
+  enabled: true
+  listen_addr: ":7443"
+kube_config_file_path: "` + kubeConfigPath + `"
+`
+		configPath := filepath.Join(tempDir, "config.yaml")
+		err := os.WriteFile(configPath, []byte(configContent), 0600)
+		require.NoError(t, err)
+
+		// Prepare args for Load function with only config file path
+		args := []string{
+			"--" + configFilePathFlagName + "=" + configPath,
+		}
+
+		// Load config using the full Load function
+		config, err := Load(args)
+		require.NoError(t, err)
+
+		// Assert config file values override defaults
+		assert.Equal(t, configListenAddr, config.ListenAddr, "Config file should override defaults for listen address")
+		assert.True(t, config.PrometheusCR.Enabled, "Config file should override defaults for prometheus CR enabled")
+		assert.True(t, config.HTTPS.Enabled, "Config file should override defaults for HTTPS enabled")
+		assert.Equal(t, ":7443", config.HTTPS.ListenAddr, "Config file should override defaults for HTTPS listen address")
+		assert.Equal(t, kubeConfigPath, config.KubeConfigFilePath, "Config file should set kube config path")
+	})
+
+	t.Run("environment variables are applied", func(t *testing.T) {
+		// Setup: create empty config file and dummy kube config
+		tempDir := t.TempDir()
+		emptyConfigPath := filepath.Join(tempDir, "empty.yaml")
+		err := os.WriteFile(emptyConfigPath, []byte("{}"), 0600)
+		require.NoError(t, err)
+
+		kubeConfigPath := createDummyKubeConfig(t, tempDir)
+
+		// Save original env var value and restore after test
+		originalNamespace := os.Getenv("OTELCOL_NAMESPACE")
+		defer func() {
+			envErr := os.Setenv("OTELCOL_NAMESPACE", originalNamespace)
+			assert.NoError(t, envErr)
+		}()
+
+		// Set environment variable
+		testNamespace := "test-namespace"
+		err = os.Setenv("OTELCOL_NAMESPACE", testNamespace)
+		require.NoError(t, err)
+
+		// Prepare args for Load function
+		args := []string{
+			"--" + configFilePathFlagName + "=" + emptyConfigPath,
+			"--" + kubeConfigPathFlagName + "=" + kubeConfigPath,
+		}
+
+		// Load config using the full Load function
+		config, err := Load(args)
+		require.NoError(t, err)
+
+		// Assert environment variable is applied
+		assert.Equal(t, testNamespace, config.CollectorNamespace, "Environment variable should be applied")
+	})
+
+	t.Run("loading priority order: defaults <- config file <- env vars <- CLI", func(t *testing.T) {
+		// Setup: create config file with values and dummy kube config
+		tempDir := t.TempDir()
+		kubeConfigPath := createDummyKubeConfig(t, tempDir)
+
+		// Config file sets values
+		configContent := `
+collector_namespace: "config-file-namespace"
+listen_addr: ":9090"
+prometheus_cr:
+  enabled: false
+kube_config_file_path: "` + kubeConfigPath + `"
+`
+		configPath := filepath.Join(tempDir, "config.yaml")
+		err := os.WriteFile(configPath, []byte(configContent), 0600)
+		require.NoError(t, err)
+
+		// Save original env var value and restore after test
+		originalNamespace := os.Getenv("OTELCOL_NAMESPACE")
+		defer func() {
+			envErr := os.Setenv("OTELCOL_NAMESPACE", originalNamespace)
+			assert.NoError(t, envErr)
+		}()
+
+		// Environment variable sets value
+		testNamespace := "env-var-namespace"
+		err = os.Setenv("OTELCOL_NAMESPACE", testNamespace)
+		require.NoError(t, err)
+
+		// Prepare args for Load function with CLI values
+		cliListenAddr := ":8888"
+		args := []string{
+			"--" + configFilePathFlagName + "=" + configPath,
+			"--" + listenAddrFlagName + "=" + cliListenAddr,
+			"--" + prometheusCREnabledFlagName + "=true",
+		}
+
+		// Load config using the full Load function
+		config, err := Load(args)
+		require.NoError(t, err)
+
+		// Assert correct priority: CLI over env vars over config file over defaults
+		assert.Equal(t, testNamespace, config.CollectorNamespace, "Env var should override config file for namespace")
+		assert.Equal(t, cliListenAddr, config.ListenAddr, "CLI should override config file for listen address")
+		assert.True(t, config.PrometheusCR.Enabled, "CLI should override config file for prometheus CR enabled")
+	})
+}
diff --git a/cmd/otel-allocator/internal/config/flags_test.go b/cmd/otel-allocator/internal/config/flags_test.go
index f1ea0de2..5c76da9a 100644
--- a/cmd/otel-allocator/internal/config/flags_test.go
+++ b/cmd/otel-allocator/internal/config/flags_test.go
@@ -39,20 +39,26 @@ func TestFlagGetters(t *testing.T) {
 			name:          "GetKubeConfigFilePath",
 			flagArgs:      []string{"--" + kubeConfigPathFlagName, filepath.Join("~", ".kube", "config")},
 			expectedValue: filepath.Join("~", ".kube", "config"),
-			getterFunc:    func(fs *pflag.FlagSet) (interface{}, error) { return getKubeConfigFilePath(fs) },
+			getterFunc: func(fs *pflag.FlagSet) (interface{}, error) {
+				value, _, err := getKubeConfigFilePath(fs)
+				return value, err
+			},
 		},
 		{
 			name:          "GetListenAddr",
 			flagArgs:      []string{"--" + listenAddrFlagName, ":8081"},
 			expectedValue: ":8081",
-			getterFunc:    func(fs *pflag.FlagSet) (interface{}, error) { return getListenAddr(fs) },
+			getterFunc: func(fs *pflag.FlagSet) (interface{}, error) {
+				value, _, err := getListenAddr(fs)
+				return value, err
+			},
 		},
 		{
 			name:          "GetPrometheusCREnabled",
 			flagArgs:      []string{"--" + prometheusCREnabledFlagName, "true"},
 			expectedValue: true,
 			getterFunc: func(fs *pflag.FlagSet) (interface{}, error) {
-				_, value, err := getPrometheusCREnabled(fs)
+				value, _, err := getPrometheusCREnabled(fs)
 				return value, err
 			},
 		},
diff --git a/tests/e2e-instrumentation/instrumentation-dotnet-multicontainer/00-install-collector.yaml b/tests/e2e-instrumentation/instrumentation-dotnet-multicontainer/00-install-collector.yaml
index 5db3bc0a..35568d28 100644
--- a/tests/e2e-instrumentation/instrumentation-dotnet-multicontainer/00-install-collector.yaml
+++ b/tests/e2e-instrumentation/instrumentation-dotnet-multicontainer/00-install-collector.yaml
@@ -1,22 +1,27 @@
-apiVersion: opentelemetry.io/v1alpha1
+apiVersion: opentelemetry.io/v1beta1
 kind: OpenTelemetryCollector
 metadata:
   name: sidecar
 spec:
   mode: sidecar
-  config: |
+  config:
     receivers:
       otlp:
         protocols:
-          grpc:
-          http:
-    processors:
+          grpc: {}
+          http: {}
+
+    processors: {}
 
     exporters:
       debug:
+        verbosity: detailed
 
     service:
       pipelines:
         traces:
           receivers: [otlp]
           exporters: [debug]
+        metrics:
+          receivers: [otlp]
+          exporters: [debug]
diff --git a/tests/e2e-instrumentation/instrumentation-dotnet-multicontainer/00-install-instrumentation.yaml b/tests/e2e-instrumentation/instrumentation-dotnet-multicontainer/00-install-instrumentation.yaml
index 71351ee4..312606fe 100644
--- a/tests/e2e-instrumentation/instrumentation-dotnet-multicontainer/00-install-instrumentation.yaml
+++ b/tests/e2e-instrumentation/instrumentation-dotnet-multicontainer/00-install-instrumentation.yaml
@@ -7,24 +7,15 @@ spec:
     - name: OTEL_TRACES_EXPORTER
       value: otlp
     - name: OTEL_EXPORTER_OTLP_ENDPOINT
-      value: http://localhost:4317
+      value: http://localhost:4318
     - name: OTEL_EXPORTER_OTLP_TIMEOUT
-      value: "20"
+      value: "20000"
     - name: OTEL_TRACES_SAMPLER
-      value: parentbased_traceidratio
-    - name: OTEL_TRACES_SAMPLER_ARG
-      value: "0.85"
+      value: always_on
     - name: SPLUNK_TRACE_RESPONSE_HEADER_ENABLED
       value: "true"
   exporter:
-    endpoint: http://localhost:4317
+    endpoint: http://localhost:4318
   propagators:
     - jaeger
     - b3multi
-  sampler:
-    type: parentbased_traceidratio
-    argument: "0.25"
-  dotnet:
-    env:
-      - name: OTEL_LOG_LEVEL
-        value: "debug"
\ No newline at end of file
diff --git a/tests/e2e-instrumentation/instrumentation-dotnet-multicontainer/01-assert.yaml b/tests/e2e-instrumentation/instrumentation-dotnet-multicontainer/01-assert.yaml
index 91ecb811..5ea35016 100644
--- a/tests/e2e-instrumentation/instrumentation-dotnet-multicontainer/01-assert.yaml
+++ b/tests/e2e-instrumentation/instrumentation-dotnet-multicontainer/01-assert.yaml
@@ -13,15 +13,15 @@ spec:
     - name: OTEL_NODE_IP
       valueFrom:
         fieldRef:
+          apiVersion: v1
           fieldPath: status.hostIP
     - name: OTEL_POD_IP
       valueFrom:
         fieldRef:
+          apiVersion: v1
           fieldPath: status.podIP
     - name: ASPNETCORE_URLS
       value: http://+:8080
-    - name: OTEL_LOG_LEVEL
-      value: debug
     - name: CORECLR_ENABLE_PROFILING
       value: "1"
     - name: CORECLR_PROFILER
@@ -39,13 +39,11 @@ spec:
     - name: OTEL_TRACES_EXPORTER
       value: otlp
     - name: OTEL_EXPORTER_OTLP_ENDPOINT
-      value: http://localhost:4317
+      value: http://localhost:4318
     - name: OTEL_EXPORTER_OTLP_TIMEOUT
-      value: "20"
+      value: "20000"
     - name: OTEL_TRACES_SAMPLER
-      value: parentbased_traceidratio
-    - name: OTEL_TRACES_SAMPLER_ARG
-      value: "0.85"
+      value: always_on
     - name: SPLUNK_TRACE_RESPONSE_HEADER_ENABLED
       value: "true"
     - name: OTEL_SERVICE_NAME
@@ -64,6 +62,9 @@ spec:
       value: jaeger,b3multi
     - name: OTEL_RESOURCE_ATTRIBUTES
     name: myapp
+    ports:
+    - containerPort: 8080
+      protocol: TCP
     volumeMounts:
     - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
       readOnly: true
@@ -73,13 +74,13 @@ spec:
     - name: OTEL_NODE_IP
       valueFrom:
         fieldRef:
+          apiVersion: v1
           fieldPath: status.hostIP
     - name: OTEL_POD_IP
       valueFrom:
         fieldRef:
+          apiVersion: v1
           fieldPath: status.podIP
-    - name: OTEL_LOG_LEVEL
-      value: debug
     - name: CORECLR_ENABLE_PROFILING
       value: "1"
     - name: CORECLR_PROFILER
@@ -97,13 +98,11 @@ spec:
     - name: OTEL_TRACES_EXPORTER
       value: otlp
     - name: OTEL_EXPORTER_OTLP_ENDPOINT
-      value: http://localhost:4317
+      value: http://localhost:4318
     - name: OTEL_EXPORTER_OTLP_TIMEOUT
-      value: "20"
+      value: "20000"
     - name: OTEL_TRACES_SAMPLER
-      value: parentbased_traceidratio
-    - name: OTEL_TRACES_SAMPLER_ARG
-      value: "0.85"
+      value: always_on
     - name: SPLUNK_TRACE_RESPONSE_HEADER_ENABLED
       value: "true"
     - name: OTEL_SERVICE_NAME
diff --git a/tests/e2e-instrumentation/instrumentation-dotnet-multicontainer/01-install-app.yaml b/tests/e2e-instrumentation/instrumentation-dotnet-multicontainer/01-install-app.yaml
index 65681d5b..86407fcd 100644
--- a/tests/e2e-instrumentation/instrumentation-dotnet-multicontainer/01-install-app.yaml
+++ b/tests/e2e-instrumentation/instrumentation-dotnet-multicontainer/01-install-app.yaml
@@ -22,6 +22,8 @@ spec:
         fsGroup: 3000
       containers:
       - name: myapp
+        ports:
+        - containerPort: 8080
         image: ghcr.io/open-telemetry/opentelemetry-operator/e2e-test-app-dotnet:main
         securityContext:
           allowPrivilegeEscalation: false
@@ -30,6 +32,15 @@ spec:
         env:
         - name: ASPNETCORE_URLS
           value: "http://+:8080"
+        readinessProbe:
+          httpGet:
+            path: /rolldice
+            port: 8080
+            scheme: HTTP
+          initialDelaySeconds: 5
+          periodSeconds: 15
+          timeoutSeconds: 2
+          failureThreshold: 3
       - name: myrabbit
         image: rabbitmq:3
         securityContext:
diff --git a/tests/e2e-instrumentation/instrumentation-dotnet-multicontainer/02-assert.yaml b/tests/e2e-instrumentation/instrumentation-dotnet-multicontainer/02-assert.yaml
index dfda2367..339fdb6a 100644
--- a/tests/e2e-instrumentation/instrumentation-dotnet-multicontainer/02-assert.yaml
+++ b/tests/e2e-instrumentation/instrumentation-dotnet-multicontainer/02-assert.yaml
@@ -24,15 +24,15 @@ spec:
     - name: OTEL_NODE_IP
       valueFrom:
         fieldRef:
+          apiVersion: v1
           fieldPath: status.hostIP
     - name: OTEL_POD_IP
       valueFrom:
         fieldRef:
+          apiVersion: v1
           fieldPath: status.podIP
     - name: ASPNETCORE_URLS
       value: http://+:8080
-    - name: OTEL_LOG_LEVEL
-      value: debug
     - name: CORECLR_ENABLE_PROFILING
       value: "1"
     - name: CORECLR_PROFILER
@@ -50,13 +50,11 @@ spec:
     - name: OTEL_TRACES_EXPORTER
       value: otlp
     - name: OTEL_EXPORTER_OTLP_ENDPOINT
-      value: http://localhost:4317
+      value: http://localhost:4318
     - name: OTEL_EXPORTER_OTLP_TIMEOUT
-      value: "20"
+      value: "20000"
     - name: OTEL_TRACES_SAMPLER
-      value: parentbased_traceidratio
-    - name: OTEL_TRACES_SAMPLER_ARG
-      value: "0.85"
+      value: always_on
     - name: SPLUNK_TRACE_RESPONSE_HEADER_ENABLED
       value: "true"
     - name: OTEL_SERVICE_NAME
@@ -74,6 +72,10 @@ spec:
     - name: OTEL_PROPAGATORS
       value: jaeger,b3multi
     - name: OTEL_RESOURCE_ATTRIBUTES
+    name: myapp
+    ports:
+    - containerPort: 8080
+      protocol: TCP
     volumeMounts:
     - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
       readOnly: true
diff --git a/tests/e2e-instrumentation/instrumentation-dotnet-multicontainer/02-install-app.yaml b/tests/e2e-instrumentation/instrumentation-dotnet-multicontainer/02-install-app.yaml
index d6bea125..fdef18c0 100644
--- a/tests/e2e-instrumentation/instrumentation-dotnet-multicontainer/02-install-app.yaml
+++ b/tests/e2e-instrumentation/instrumentation-dotnet-multicontainer/02-install-app.yaml
@@ -22,6 +22,8 @@ spec:
         fsGroup: 3000
       containers:
       - name: myapp
+        ports:
+        - containerPort: 8080
         image: ghcr.io/open-telemetry/opentelemetry-operator/e2e-test-app-dotnet:main
         securityContext:
           allowPrivilegeEscalation: false
@@ -30,6 +32,15 @@ spec:
         env:
         - name: ASPNETCORE_URLS
           value: "http://+:8080"
+        readinessProbe:
+          httpGet:
+            path: /rolldice
+            port: 8080
+            scheme: HTTP
+          initialDelaySeconds: 5
+          periodSeconds: 15
+          timeoutSeconds: 2
+          failureThreshold: 3
       - name: myrabbit
         image: rabbitmq:3
         securityContext:
diff --git a/tests/e2e-instrumentation/instrumentation-dotnet-multicontainer/chainsaw-test.yaml b/tests/e2e-instrumentation/instrumentation-dotnet-multicontainer/chainsaw-test.yaml
index 13ff6abb..1c8e9250 100755
--- a/tests/e2e-instrumentation/instrumentation-dotnet-multicontainer/chainsaw-test.yaml
+++ b/tests/e2e-instrumentation/instrumentation-dotnet-multicontainer/chainsaw-test.yaml
@@ -40,12 +40,197 @@ spec:
     catch:
       - podLogs:
           selector: app=my-dotnet-multi
+  - name: Make a request to the app
+    try:
+      - command:
+          entrypoint: kubectl
+          args:
+            - get
+            - pod
+            - -n
+            - ${NAMESPACE}
+            - -l
+            - app=my-dotnet-multi
+            - -o
+            - jsonpath={.items[0].metadata.name}
+          outputs:
+          - name: podName
+            value: ($stdout)
+      - proxy:
+          apiVersion: v1
+          kind: Pod
+          name: ($podName)
+          namespace: ${NAMESPACE}
+          port: "8080"
+          path: /rolldice
+  - name: Wait for telemetry data
+    try:
+    - script:
+        env:
+          - name: LABEL_SELECTOR
+            value: "app=my-dotnet-multi"
+          - name: CONTAINER_NAME
+            value: "otc-container" 
+          - name: RETRY_TIMEOUT
+            value: "120"
+          - name: RETRY_SLEEP
+            value: "5"
+          - name: SEARCH_STRINGS_ENV
+            value: |
+              Name: process.runtime.dotnet.gc.collections.count
+              Description: Number of garbage collections that have occurred since process start
+        timeout: 2m
+        content: ../../test-e2e-apps/scripts/check_pod_logs.sh
+  - name: Check the instrumented app has sent the telemetry data successfully
+    try:
+      - command:
+          entrypoint: kubectl
+          args:
+            - get
+            - pod
+            - -n
+            - ${NAMESPACE}
+            - -l
+            - app=my-dotnet-multi
+            - -o
+            - jsonpath={.items[0].metadata.name}
+          outputs:
+          - name: podName
+            value: ($stdout)
+      - script:
+          env:
+          - name: podName
+            value: ($podName)
+          content: |
+            #!/bin/bash
+            # set -ex
+            kubectl get --raw /api/v1/namespaces/$NAMESPACE/pods/${podName}:8888/proxy/metrics
+          outputs:
+          - name: metrics
+            value: (x_metrics_decode($stdout))
+          check:
+            ($error == null): true
+      - assert:
+          resource:
+            ($metrics[?as_string(metric."__name__") == 'otelcol_exporter_sent_spans_total'].value | [0] > `1`): true
+            ($metrics[?as_string(metric."__name__") == 'otelcol_receiver_accepted_spans_total'].value | [0] > `1`): true
+            ($metrics[?as_string(metric."__name__") == 'otelcol_exporter_sent_metric_points_total'].value | [0] > `1`): true
+            ($metrics[?as_string(metric."__name__") == 'otelcol_receiver_accepted_metric_points_total'].value | [0] > `1`): true
+    catch:
+      - podLogs:
+          selector: app=my-dotnet-multi
+          container: otc-container
   - name: step-03
     try:
+    - command:
+        env:
+        - name: appnamespace
+          value: ($namespace)
+        entrypoint: kubectl
+        args:
+          - get
+          - pod
+          - -n
+          - $appnamespace
+          - -l
+          - app=my-dotnet-multi
+          - -o
+          - jsonpath={.items[0].metadata.name}
+        outputs:
+        - name: podName
+          value: ($stdout)
     - apply:
         file: 02-install-app.yaml
     - assert:
         file: 02-assert.yaml
+    - wait:
+        apiVersion: v1
+        kind: Pod
+        name: ($podName)
+        namespace: ($namespace)
+        timeout: 1m
+        for:
+          deletion: {}
+    catch:
+      - podLogs:
+          selector: app=my-dotnet-multi
+  - name: Make a request to the app
+    try:
+      - command:
+          entrypoint: kubectl
+          args:
+            - get
+            - pod
+            - -n
+            - ${NAMESPACE}
+            - -l
+            - app=my-dotnet-multi
+            - -o
+            - jsonpath={.items[0].metadata.name}
+          outputs:
+          - name: podName
+            value: ($stdout)
+      - proxy:
+          apiVersion: v1
+          kind: Pod
+          name: ($podName)
+          namespace: ${NAMESPACE}
+          port: "8080"
+          path: /rolldice
+  - name: Wait for telemetry data
+    try:
+    - script:
+        env:
+          - name: LABEL_SELECTOR
+            value: "app=my-dotnet-multi"
+          - name: CONTAINER_NAME
+            value: "otc-container" 
+          - name: RETRY_TIMEOUT
+            value: "120"
+          - name: RETRY_SLEEP
+            value: "5"
+          - name: SEARCH_STRINGS_ENV
+            value: |
+              Name: process.runtime.dotnet.gc.collections.count
+              Description: Number of garbage collections that have occurred since process start
+        timeout: 2m
+        content: ../../test-e2e-apps/scripts/check_pod_logs.sh
+  - name: Check the instrumented app has sent the telemetry data successfully
+    try:
+      - command:
+          entrypoint: kubectl
+          args:
+            - get
+            - pod
+            - -n
+            - ${NAMESPACE}
+            - -l
+            - app=my-dotnet-multi
+            - -o
+            - jsonpath={.items[0].metadata.name}
+          outputs:
+          - name: podName
+            value: ($stdout)
+      - script:
+          env:
+          - name: podName
+            value: ($podName)
+          content: |
+            #!/bin/bash
+            # set -ex
+            kubectl get --raw /api/v1/namespaces/$NAMESPACE/pods/${podName}:8888/proxy/metrics
+          outputs:
+          - name: metrics
+            value: (x_metrics_decode($stdout))
+          check:
+            ($error == null): true
+      - assert:
+          resource:
+            ($metrics[?as_string(metric."__name__") == 'otelcol_exporter_sent_spans_total'].value | [0] > `1`): true
+            ($metrics[?as_string(metric."__name__") == 'otelcol_receiver_accepted_spans_total'].value | [0] > `1`): true
+            ($metrics[?as_string(metric."__name__") == 'otelcol_exporter_sent_metric_points_total'].value | [0] > `1`): true
+            ($metrics[?as_string(metric."__name__") == 'otelcol_receiver_accepted_metric_points_total'].value | [0] > `1`): true
     catch:
       - podLogs:
           selector: app=my-dotnet-multi
+          container: otc-container
diff --git a/tests/e2e-instrumentation/instrumentation-dotnet-musl/00-install-collector.yaml b/tests/e2e-instrumentation/instrumentation-dotnet-musl/00-install-collector.yaml
index 34a26ebb..e32ff2b4 100644
--- a/tests/e2e-instrumentation/instrumentation-dotnet-musl/00-install-collector.yaml
+++ b/tests/e2e-instrumentation/instrumentation-dotnet-musl/00-install-collector.yaml
@@ -1,22 +1,27 @@
-apiVersion: opentelemetry.io/v1alpha1
+apiVersion: opentelemetry.io/v1beta1
 kind: OpenTelemetryCollector
 metadata:
   name: sidecar
 spec:
-  config: |
+  config:
     receivers:
       otlp:
         protocols:
-          grpc:
-          http:
-    processors:
+          grpc: {}
+          http: {}
+
+    processors: {}
 
     exporters:
       debug:
+        verbosity: detailed
 
     service:
       pipelines:
         traces:
           receivers: [otlp]
           exporters: [debug]
+        metrics:
+          receivers: [otlp]
+          exporters: [debug]
   mode: sidecar
diff --git a/tests/e2e-instrumentation/instrumentation-dotnet-musl/00-install-instrumentation.yaml b/tests/e2e-instrumentation/instrumentation-dotnet-musl/00-install-instrumentation.yaml
index 80ca25ca..312606fe 100644
--- a/tests/e2e-instrumentation/instrumentation-dotnet-musl/00-install-instrumentation.yaml
+++ b/tests/e2e-instrumentation/instrumentation-dotnet-musl/00-install-instrumentation.yaml
@@ -7,20 +7,15 @@ spec:
     - name: OTEL_TRACES_EXPORTER
       value: otlp
     - name: OTEL_EXPORTER_OTLP_ENDPOINT
-      value: http://localhost:4317
+      value: http://localhost:4318
     - name: OTEL_EXPORTER_OTLP_TIMEOUT
-      value: "20"
+      value: "20000"
     - name: OTEL_TRACES_SAMPLER
-      value: parentbased_traceidratio
-    - name: OTEL_TRACES_SAMPLER_ARG
-      value: "0.85"
+      value: always_on
     - name: SPLUNK_TRACE_RESPONSE_HEADER_ENABLED
       value: "true"
   exporter:
-    endpoint: http://localhost:4317
+    endpoint: http://localhost:4318
   propagators:
     - jaeger
     - b3multi
-  sampler:
-    type: parentbased_traceidratio
-    argument: "0.25"
diff --git a/tests/e2e-instrumentation/instrumentation-dotnet-musl/01-assert.yaml b/tests/e2e-instrumentation/instrumentation-dotnet-musl/01-assert.yaml
index 08afb751..b564520e 100644
--- a/tests/e2e-instrumentation/instrumentation-dotnet-musl/01-assert.yaml
+++ b/tests/e2e-instrumentation/instrumentation-dotnet-musl/01-assert.yaml
@@ -3,7 +3,7 @@ kind: Pod
 metadata:
   annotations:
     instrumentation.opentelemetry.io/inject-dotnet: "true"
-    sidecar.opentelemetry.io/inject: "true"
+    instrumentation.opentelemetry.io/otel-dotnet-auto-runtime: linux-musl-x64
   labels:
     app: my-dotnet-musl
 spec:
@@ -12,10 +12,12 @@ spec:
     - name: OTEL_NODE_IP
       valueFrom:
         fieldRef:
+          apiVersion: v1
           fieldPath: status.hostIP
     - name: OTEL_POD_IP
       valueFrom:
         fieldRef:
+          apiVersion: v1
           fieldPath: status.podIP
     - name: ASPNETCORE_URLS
       value: http://+:8080
@@ -36,13 +38,11 @@ spec:
     - name: OTEL_TRACES_EXPORTER
       value: otlp
     - name: OTEL_EXPORTER_OTLP_ENDPOINT
-      value: http://localhost:4317
+      value: http://localhost:4318
     - name: OTEL_EXPORTER_OTLP_TIMEOUT
-      value: "20"
+      value: "20000"
     - name: OTEL_TRACES_SAMPLER
-      value: parentbased_traceidratio
-    - name: OTEL_TRACES_SAMPLER_ARG
-      value: "0.85"
+      value: always_on
     - name: SPLUNK_TRACE_RESPONSE_HEADER_ENABLED
       value: "true"
     - name: OTEL_SERVICE_NAME
@@ -61,6 +61,9 @@ spec:
       value: jaeger,b3multi
     - name: OTEL_RESOURCE_ATTRIBUTES
     name: myapp
+    ports:
+    - containerPort: 8080
+      protocol: TCP
     volumeMounts:
     - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
       readOnly: true
diff --git a/tests/e2e-instrumentation/instrumentation-dotnet-musl/01-install-app.yaml b/tests/e2e-instrumentation/instrumentation-dotnet-musl/01-install-app.yaml
index b69d2fb3..589346e7 100644
--- a/tests/e2e-instrumentation/instrumentation-dotnet-musl/01-install-app.yaml
+++ b/tests/e2e-instrumentation/instrumentation-dotnet-musl/01-install-app.yaml
@@ -22,6 +22,8 @@ spec:
         fsGroup: 3000
       containers:
       - name: myapp
+        ports:
+        - containerPort: 8080
         image: ghcr.io/open-telemetry/opentelemetry-operator/e2e-test-app-dotnet:main
         securityContext:
           allowPrivilegeEscalation: false
@@ -30,3 +32,12 @@ spec:
         env:
         - name: ASPNETCORE_URLS
           value: "http://+:8080"
+        readinessProbe:
+          httpGet:
+            path: /rolldice
+            port: 8080
+            scheme: HTTP
+          initialDelaySeconds: 5
+          periodSeconds: 15
+          timeoutSeconds: 2
+          failureThreshold: 3
diff --git a/tests/e2e-instrumentation/instrumentation-dotnet/00-install-collector.yaml b/tests/e2e-instrumentation/instrumentation-dotnet/00-install-collector.yaml
index 34a26ebb..e32ff2b4 100644
--- a/tests/e2e-instrumentation/instrumentation-dotnet/00-install-collector.yaml
+++ b/tests/e2e-instrumentation/instrumentation-dotnet/00-install-collector.yaml
@@ -1,22 +1,27 @@
-apiVersion: opentelemetry.io/v1alpha1
+apiVersion: opentelemetry.io/v1beta1
 kind: OpenTelemetryCollector
 metadata:
   name: sidecar
 spec:
-  config: |
+  config:
     receivers:
       otlp:
         protocols:
-          grpc:
-          http:
-    processors:
+          grpc: {}
+          http: {}
+
+    processors: {}
 
     exporters:
       debug:
+        verbosity: detailed
 
     service:
       pipelines:
         traces:
           receivers: [otlp]
           exporters: [debug]
+        metrics:
+          receivers: [otlp]
+          exporters: [debug]
   mode: sidecar
diff --git a/tests/e2e-instrumentation/instrumentation-dotnet/00-install-instrumentation.yaml b/tests/e2e-instrumentation/instrumentation-dotnet/00-install-instrumentation.yaml
index 80ca25ca..312606fe 100644
--- a/tests/e2e-instrumentation/instrumentation-dotnet/00-install-instrumentation.yaml
+++ b/tests/e2e-instrumentation/instrumentation-dotnet/00-install-instrumentation.yaml
@@ -7,20 +7,15 @@ spec:
     - name: OTEL_TRACES_EXPORTER
       value: otlp
     - name: OTEL_EXPORTER_OTLP_ENDPOINT
-      value: http://localhost:4317
+      value: http://localhost:4318
     - name: OTEL_EXPORTER_OTLP_TIMEOUT
-      value: "20"
+      value: "20000"
     - name: OTEL_TRACES_SAMPLER
-      value: parentbased_traceidratio
-    - name: OTEL_TRACES_SAMPLER_ARG
-      value: "0.85"
+      value: always_on
     - name: SPLUNK_TRACE_RESPONSE_HEADER_ENABLED
       value: "true"
   exporter:
-    endpoint: http://localhost:4317
+    endpoint: http://localhost:4318
   propagators:
     - jaeger
     - b3multi
-  sampler:
-    type: parentbased_traceidratio
-    argument: "0.25"
diff --git a/tests/e2e-instrumentation/instrumentation-dotnet/01-assert.yaml b/tests/e2e-instrumentation/instrumentation-dotnet/01-assert.yaml
index 1318ded2..c0e3b79f 100644
--- a/tests/e2e-instrumentation/instrumentation-dotnet/01-assert.yaml
+++ b/tests/e2e-instrumentation/instrumentation-dotnet/01-assert.yaml
@@ -12,10 +12,12 @@ spec:
     - name: OTEL_NODE_IP
       valueFrom:
         fieldRef:
+          apiVersion: v1
           fieldPath: status.hostIP
     - name: OTEL_POD_IP
       valueFrom:
         fieldRef:
+          apiVersion: v1
           fieldPath: status.podIP
     - name: ASPNETCORE_URLS
       value: http://+:8080
@@ -36,13 +38,11 @@ spec:
     - name: OTEL_TRACES_EXPORTER
       value: otlp
     - name: OTEL_EXPORTER_OTLP_ENDPOINT
-      value: http://localhost:4317
+      value: http://localhost:4318
     - name: OTEL_EXPORTER_OTLP_TIMEOUT
-      value: "20"
+      value: "20000"
     - name: OTEL_TRACES_SAMPLER
-      value: parentbased_traceidratio
-    - name: OTEL_TRACES_SAMPLER_ARG
-      value: "0.85"
+      value: always_on
     - name: SPLUNK_TRACE_RESPONSE_HEADER_ENABLED
       value: "true"
     - name: OTEL_SERVICE_NAME
@@ -61,6 +61,9 @@ spec:
       value: jaeger,b3multi
     - name: OTEL_RESOURCE_ATTRIBUTES
     name: myapp
+    ports:
+    - containerPort: 8080
+      protocol: TCP
     volumeMounts:
     - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
       readOnly: true
diff --git a/tests/e2e-instrumentation/instrumentation-dotnet/01-install-app.yaml b/tests/e2e-instrumentation/instrumentation-dotnet/01-install-app.yaml
index 4a80480f..33fead0a 100644
--- a/tests/e2e-instrumentation/instrumentation-dotnet/01-install-app.yaml
+++ b/tests/e2e-instrumentation/instrumentation-dotnet/01-install-app.yaml
@@ -21,6 +21,8 @@ spec:
         fsGroup: 3000
       containers:
       - name: myapp
+        ports:
+        - containerPort: 8080
         image: ghcr.io/open-telemetry/opentelemetry-operator/e2e-test-app-dotnet:main
         securityContext:
           allowPrivilegeEscalation: false
@@ -29,3 +31,12 @@ spec:
         env:
         - name: ASPNETCORE_URLS
           value: "http://+:8080"
+        readinessProbe:
+          httpGet:
+            path: /rolldice
+            port: 8080
+            scheme: HTTP
+          initialDelaySeconds: 5
+          periodSeconds: 15
+          timeoutSeconds: 2
+          failureThreshold: 3
diff --git a/tests/e2e-instrumentation/instrumentation-dotnet/chainsaw-test.yaml b/tests/e2e-instrumentation/instrumentation-dotnet/chainsaw-test.yaml
index bdd2fd9a..84c02ae8 100755
--- a/tests/e2e-instrumentation/instrumentation-dotnet/chainsaw-test.yaml
+++ b/tests/e2e-instrumentation/instrumentation-dotnet/chainsaw-test.yaml
@@ -38,3 +38,83 @@ spec:
     catch:
       - podLogs:
           selector: app=my-dotnet
+  - name: Make a request to the app
+    try:
+      - command:
+          entrypoint: kubectl
+          args:
+            - get
+            - pod
+            - -n
+            - ${NAMESPACE}
+            - -l
+            - app=my-dotnet
+            - -o
+            - jsonpath={.items[0].metadata.name}
+          outputs:
+          - name: podName
+            value: ($stdout)
+      - proxy:
+          apiVersion: v1
+          kind: Pod
+          name: ($podName)
+          namespace: ${NAMESPACE}
+          port: "8080"
+          path: /rolldice
+  - name: Wait for telemetry data
+    try:
+    - script:
+        env:
+          - name: LABEL_SELECTOR
+            value: "app=my-dotnet"
+          - name: CONTAINER_NAME
+            value: "otc-container" 
+          - name: RETRY_TIMEOUT
+            value: "120"
+          - name: RETRY_SLEEP
+            value: "5"
+          - name: SEARCH_STRINGS_ENV
+            value: |
+              Name: process.runtime.dotnet.gc.collections.count
+              Description: Number of garbage collections that have occurred since process start
+        timeout: 2m
+        content: ../../test-e2e-apps/scripts/check_pod_logs.sh
+  - name: Check the instrumented app has sent the telemetry data successfully
+    try:
+      - command:
+          entrypoint: kubectl
+          args:
+            - get
+            - pod
+            - -n
+            - ${NAMESPACE}
+            - -l
+            - app=my-dotnet
+            - -o
+            - jsonpath={.items[0].metadata.name}
+          outputs:
+          - name: podName
+            value: ($stdout)
+      - script:
+          env:
+          - name: podName
+            value: ($podName)
+          content: |
+            #!/bin/bash
+            # set -ex
+            kubectl get --raw /api/v1/namespaces/$NAMESPACE/pods/${podName}:8888/proxy/metrics
+          outputs:
+          - name: metrics
+            value: (x_metrics_decode($stdout))
+          check:
+            ($error == null): true
+      - assert:
+          resource:
+            ($metrics[?as_string(metric."__name__") == 'otelcol_exporter_sent_spans_total'].value | [0] > `1`): true
+            ($metrics[?as_string(metric."__name__") == 'otelcol_receiver_accepted_spans_total'].value | [0] > `1`): true
+            ($metrics[?as_string(metric."__name__") == 'otelcol_exporter_sent_metric_points_total'].value | [0] > `1`): true
+            ($metrics[?as_string(metric."__name__") == 'otelcol_receiver_accepted_metric_points_total'].value | [0] > `1`): true
+    catch:
+      - podLogs:
+          selector: app=my-dotnet
+          container: otc-container
diff --git a/tests/test-e2e-apps/golang/Dockerfile b/tests/test-e2e-apps/golang/Dockerfile
index 6964ccd0..9b292613 100644
--- a/tests/test-e2e-apps/golang/Dockerfile
+++ b/tests/test-e2e-apps/golang/Dockerfile
@@ -1,8 +1,30 @@
-FROM golang:1.23-alpine as builder
+# Stage 1: Build the Go application
+FROM golang:1.23.0-alpine AS builder
 
+# Set the working directory inside the container for the build stage.
+WORKDIR /app
+
+# Copy the Go source file into the working directory inside the container.
 COPY main.go .
-RUN CGO_ENABLED=0 GOOS=linux GO111MODULE=on go build -o app main.go
 
+# Build the Go application.
+# - CGO_ENABLED=0: Disables CGO, which is necessary to build a statically linked binary
+#   that can run in a minimal 'scratch' image without external C libraries.
+# - GOOS=linux: Explicitly sets the target operating system to Linux, which is standard for containers.
+# -o /app/rolldice: Specifies the output path and name for the compiled executable inside this builder stage.
+# main.go: The source file to compile.
+RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-w -s" -o /app/rolldice main.go
+
+# Stage 2: Create the final minimal production image
 FROM scratch
-COPY --from=builder /go/app .
-ENTRYPOINT ["./app"]
+
+# Set the working directory for the final image.
+WORKDIR /
+
+# Copy only the compiled binary from the 'builder' stage (/app/rolldice)
+# into the root directory of the final 'scratch' image.
+COPY --from=builder /app/rolldice /rolldice
+
+# Set the command to run when the container starts.
+# This executes the compiled Go binary we copied into the image.
+ENTRYPOINT ["/rolldice"]
diff --git a/tests/test-e2e-apps/golang/main.go b/tests/test-e2e-apps/golang/main.go
index a911a8f5..76f43aa5 100644
--- a/tests/test-e2e-apps/golang/main.go
+++ b/tests/test-e2e-apps/golang/main.go
@@ -4,23 +4,106 @@
 package main
 
 import (
+	"crypto/rand"
 	"fmt"
+	"log"
+	"math/big"
 	"net/http"
+	"os"
+	"strconv"
 	"time"
 )
 
+// getRandomNumber generates a random integer between min and max (inclusive).
+func getRandomNumber(min, max int) (int, error) {
+	if min > max {
+		return 0, fmt.Errorf("min (%d) cannot be greater than max (%d)", min, max)
+	}
+
+	// Calculate the range size.
+	rangeSize := big.NewInt(int64(max - min + 1))
+
+	// Generate a random number n, where 0 <= n < rangeSize.
+	n, err := rand.Int(rand.Reader, rangeSize)
+	if err != nil {
+		// Return an error if random number generation fails
+		return 0, fmt.Errorf("failed to generate random number: %w", err)
+	}
+
+	// Convert the big.Int result back to a regular int.
+	// Add min to shift the range from [0, rangeSize) to [min, max].
+	// n.Int64() is safe here because rangeSize fits in int64 if max-min+1 does.
+	result := int(n.Int64()) + min
+	return result, nil
+}
+
+// rollDiceHandler handles requests to the /rolldice endpoint.
+func rollDiceHandler(w http.ResponseWriter, r *http.Request) {
+	// Ensure we only handle GET requests for this endpoint
+	if r.Method != http.MethodGet {
+		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
+		return
+	}
+
+	// Generate a random number between 1 and 6
+	diceRoll, err := getRandomNumber(1, 6)
+	if err != nil {
+		// Log the error and return an internal server error if generation failed
+		log.Printf("Error generating random number: %v", err)
+		http.Error(w, "Internal Server Error", http.StatusInternalServerError)
+		return
+	}
+
+	// Convert the integer result to a string
+	responseString := strconv.Itoa(diceRoll)
+
+	// Set the content type header to text/plain
+	w.Header().Set("Content-Type", "text/plain")
+
+	// Write the string response back to the client
+	_, writeErr := fmt.Fprint(w, responseString)
+	if writeErr != nil {
+		// Log the error if writing the response failed (response may be partially sent)
+		log.Printf("Error writing response: %v", writeErr)
+		// Attempt to send an error, though headers might already be sent
+		// http.Error(w, "Internal Server Error", http.StatusInternalServerError) // Avoid sending second error
+	}
+	log.Printf("Rolled a %d for request from %s", diceRoll, r.RemoteAddr) // Optional: Log the roll
+}
+
 func main() {
-	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
-		fmt.Println("Hi")
-	})
+	// Get the port from the environment variable, default to "8095" if not set
+	port := os.Getenv("PORT")
+	if port == "" {
+		port = "8095"
+	}
+
+	// Register the handler function for the "/rolldice" path with the DefaultServeMux.
+	http.HandleFunc("/rolldice", rollDiceHandler)
+
+	// Construct the server address string (e.g., ":8095")
+	serverAddr := ":" + port
 
+	// Configure the HTTP server with timeouts
 	server := &http.Server{
-		Addr:              ":8080",
-		ReadHeaderTimeout: 3 * time.Second,
+		Addr: serverAddr,
+		// Use DefaultServeMux by leaving Handler nil, which includes our /rolldice handler
+		Handler:      nil,
+		ReadTimeout:  10 * time.Second, // Max time to read entire request, including body
+		WriteTimeout: 10 * time.Second, // Max time to write response
+		IdleTimeout:  60 * time.Second, // Max time for connections using TCP Keep-Alive
 	}
 
+	// Print a message indicating the server is starting
+	log.Printf("Listening for requests on http://localhost:%s", port)
+
+	// Start the configured HTTP server.
+	// This ListenAndServe is now called on our configured server instance.
 	err := server.ListenAndServe()
-	if err != nil {
-		panic(err)
+	if err != nil && err != http.ErrServerClosed {
+		// Log any fatal errors encountered during server startup, ignore ErrServerClosed
+		log.Fatalf("Server failed to start or unexpectedly closed: %v", err)
+	} else if err == http.ErrServerClosed {
+		log.Println("Server shut down gracefully")
 	}
 }