diff --git a/main.go b/main.go index 56dd54d43..cf607e7bd 100644 --- a/main.go +++ b/main.go @@ -81,6 +81,24 @@ func stringFlagOrEnv(p *string, name string, envName string, defaultValue string pflag.StringVar(p, name, defaultValue, usage) } +func setLangEnvVarsForResource(langStr string, resourceStr string, resource map[string]string) { + if cpu, ok := resource["cpu"]; ok { + os.Setenv("AUTO_INSTRUMENTATION_"+langStr+"_CPU_"+resourceStr, cpu) + } + if memory, ok := resource["memory"]; ok { + os.Setenv("AUTO_INSTRUMENTATION_"+langStr+"_MEM_"+resourceStr, memory) + } +} + +func setLangEnvVars(langStr string, cfg map[string]map[string]string) { + if limits, ok := cfg["limits"]; ok { + setLangEnvVarsForResource(langStr, "LIMIT", limits) + } + if requests, ok := cfg["requests"]; ok { + setLangEnvVarsForResource(langStr, "REQUEST", requests) + } +} + func main() { // registers any flags that underlying libraries might use opts := zap.Options{} @@ -93,18 +111,19 @@ func main() { // add flags related to this operator var ( - metricsAddr string - probeAddr string - pprofAddr string - agentImage string - autoInstrumentationJava string - autoInstrumentationPython string - autoInstrumentationDotNet string - autoAnnotationConfigStr string - webhookPort int - tlsOpt tlsConfig - dcgmExporterImage string - neuronMonitorImage string + metricsAddr string + probeAddr string + pprofAddr string + agentImage string + autoInstrumentationJava string + autoInstrumentationPython string + autoInstrumentationDotNet string + autoAnnotationConfigStr string + autoInstrumentationConfigStr string + webhookPort int + tlsOpt tlsConfig + dcgmExporterImage string + neuronMonitorImage string ) pflag.StringVar(&metricsAddr, "metrics-addr", ":8080", "The address the metric endpoint binds to.") @@ -115,10 +134,27 @@ func main() { stringFlagOrEnv(&autoInstrumentationPython, "auto-instrumentation-python-image", "RELATED_IMAGE_AUTO_INSTRUMENTATION_PYTHON", fmt.Sprintf("%s:%s", autoInstrumentationPythonImageRepository, v.AutoInstrumentationPython), "The default OpenTelemetry Python instrumentation image. This image is used when no image is specified in the CustomResource.") stringFlagOrEnv(&autoInstrumentationDotNet, "auto-instrumentation-dotnet-image", "RELATED_IMAGE_AUTO_INSTRUMENTATION_DOTNET", fmt.Sprintf("%s:%s", autoInstrumentationDotNetImageRepository, v.AutoInstrumentationDotNet), "The default OpenTelemetry Dotnet instrumentation image. This image is used when no image is specified in the CustomResource.") stringFlagOrEnv(&autoAnnotationConfigStr, "auto-annotation-config", "AUTO_ANNOTATION_CONFIG", "", "The configuration for auto-annotation.") + pflag.StringVar(&autoInstrumentationConfigStr, "auto-instrumentation-config", "", "The configuration for auto-instrumentation.") stringFlagOrEnv(&dcgmExporterImage, "dcgm-exporter-image", "RELATED_IMAGE_DCGM_EXPORTER", fmt.Sprintf("%s:%s", dcgmExporterImageRepository, v.DcgmExporter), "The default DCGM Exporter image. This image is used when no image is specified in the CustomResource.") stringFlagOrEnv(&neuronMonitorImage, "neuron-monitor-image", "RELATED_IMAGE_NEURON_MONITOR", fmt.Sprintf("%s:%s", neuronMonitorImageRepository, v.NeuronMonitor), "The default Neuron monitor image. This image is used when no image is specified in the CustomResource.") pflag.Parse() + // set instrumentation cpu and memory limits in environment variables to be used for default instrumentation; default values received from https://github.com/open-telemetry/opentelemetry-operator/blob/main/apis/v1alpha1/instrumentation_webhook.go + autoInstrumentationConfig := map[string]map[string]map[string]string{"java": {"limits": {"cpu": "500m", "memory": "64Mi"}, "requests": {"cpu": "50m", "memory": "64Mi"}}, "python": {"limits": {"cpu": "500m", "memory": "32Mi"}, "requests": {"cpu": "50m", "memory": "32Mi"}}, "dotnet": {"limits": {"cpu": "500m", "memory": "128Mi"}, "requests": {"cpu": "50m", "memory": "128Mi"}}} + err := json.Unmarshal([]byte(autoInstrumentationConfigStr), &autoInstrumentationConfig) + if err != nil { + setupLog.Info(fmt.Sprintf("Using default values: %v", autoInstrumentationConfig)) + } + if javaVar, ok := autoInstrumentationConfig["java"]; ok { + setLangEnvVars("JAVA", javaVar) + } + if pythonVar, ok := autoInstrumentationConfig["python"]; ok { + setLangEnvVars("PYTHON", pythonVar) + } + if dotNetVar, ok := autoInstrumentationConfig["dotnet"]; ok { + setLangEnvVars("DOTNET", dotNetVar) + } + // set supported language instrumentation images in environment variable to be used for default instrumentation os.Setenv("AUTO_INSTRUMENTATION_JAVA", autoInstrumentationJava) os.Setenv("AUTO_INSTRUMENTATION_PYTHON", autoInstrumentationPython) diff --git a/pkg/instrumentation/defaultinstrumentation.go b/pkg/instrumentation/defaultinstrumentation.go index b0f446c1d..e9946148c 100644 --- a/pkg/instrumentation/defaultinstrumentation.go +++ b/pkg/instrumentation/defaultinstrumentation.go @@ -8,6 +8,8 @@ import ( "fmt" "os" + "k8s.io/apimachinery/pkg/api/resource" + corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -23,8 +25,30 @@ const ( http = "http" https = "https" + + java = "JAVA" + python = "PYTHON" + dotNet = "DOTNET" + limit = "LIMIT" + request = "REQUEST" ) +func getInstrumentationConfigForResource(langStr string, resourceStr string) corev1.ResourceList { + instrumentationConfigCpu, _ := os.LookupEnv("AUTO_INSTRUMENTATION_" + langStr + "_CPU_" + resourceStr) + instrumentationConfigMemory, _ := os.LookupEnv("AUTO_INSTRUMENTATION_" + langStr + "_MEM_" + resourceStr) + + instrumentationConfigForResource := corev1.ResourceList{} + instrumentationConfigCpuQuantity, err := resource.ParseQuantity(instrumentationConfigCpu) + if err == nil { + instrumentationConfigForResource[corev1.ResourceCPU] = instrumentationConfigCpuQuantity + } + instrumentationConfigMemoryQuantity, err := resource.ParseQuantity(instrumentationConfigMemory) + if err == nil { + instrumentationConfigForResource[corev1.ResourceMemory] = instrumentationConfigMemoryQuantity + } + return instrumentationConfigForResource +} + func getDefaultInstrumentation(agentConfig *adapters.CwaConfig, isWindowsPod bool) (*v1alpha1.Instrumentation, error) { javaInstrumentationImage, ok := os.LookupEnv("AUTO_INSTRUMENTATION_JAVA") if !ok { @@ -86,6 +110,10 @@ func getDefaultInstrumentation(agentConfig *adapters.CwaConfig, isWindowsPod boo {Name: "OTEL_METRICS_EXPORTER", Value: "none"}, {Name: "OTEL_LOGS_EXPORTER", Value: "none"}, }, + Resources: corev1.ResourceRequirements{ + Limits: getInstrumentationConfigForResource(java, limit), + Requests: getInstrumentationConfigForResource(java, request), + }, }, Python: v1alpha1.Python{ Image: pythonInstrumentationImage, @@ -103,6 +131,10 @@ func getDefaultInstrumentation(agentConfig *adapters.CwaConfig, isWindowsPod boo {Name: "OTEL_PYTHON_CONFIGURATOR", Value: "aws_configurator"}, {Name: "OTEL_LOGS_EXPORTER", Value: "none"}, }, + Resources: corev1.ResourceRequirements{ + Limits: getInstrumentationConfigForResource(python, limit), + Requests: getInstrumentationConfigForResource(python, request), + }, }, DotNet: v1alpha1.DotNet{ Image: dotNetInstrumentationImage, @@ -120,6 +152,10 @@ func getDefaultInstrumentation(agentConfig *adapters.CwaConfig, isWindowsPod boo {Name: "OTEL_LOGS_EXPORTER", Value: "none"}, {Name: "OTEL_DOTNET_AUTO_PLUGINS", Value: "AWS.Distro.OpenTelemetry.AutoInstrumentation.Plugin, AWS.Distro.OpenTelemetry.AutoInstrumentation"}, }, + Resources: corev1.ResourceRequirements{ + Limits: getInstrumentationConfigForResource(dotNet, limit), + Requests: getInstrumentationConfigForResource(dotNet, request), + }, }, }, }, nil diff --git a/pkg/instrumentation/defaultinstrumentation_test.go b/pkg/instrumentation/defaultinstrumentation_test.go index c553f9fac..ebe5c3f3c 100644 --- a/pkg/instrumentation/defaultinstrumentation_test.go +++ b/pkg/instrumentation/defaultinstrumentation_test.go @@ -8,6 +8,8 @@ import ( "reflect" "testing" + "k8s.io/apimachinery/pkg/api/resource" + corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -19,6 +21,18 @@ func Test_getDefaultInstrumentationLinux(t *testing.T) { os.Setenv("AUTO_INSTRUMENTATION_JAVA", defaultJavaInstrumentationImage) os.Setenv("AUTO_INSTRUMENTATION_PYTHON", defaultPythonInstrumentationImage) os.Setenv("AUTO_INSTRUMENTATION_DOTNET", defaultDotNetInstrumentationImage) + os.Setenv("AUTO_INSTRUMENTATION_JAVA_CPU_LIMIT", "500m") + os.Setenv("AUTO_INSTRUMENTATION_JAVA_MEM_LIMIT", "64Mi") + os.Setenv("AUTO_INSTRUMENTATION_JAVA_CPU_REQUEST", "50m") + os.Setenv("AUTO_INSTRUMENTATION_JAVA_MEM_REQUEST", "64Mi") + os.Setenv("AUTO_INSTRUMENTATION_PYTHON_CPU_LIMIT", "500m") + os.Setenv("AUTO_INSTRUMENTATION_PYTHON_MEM_LIMIT", "32Mi") + os.Setenv("AUTO_INSTRUMENTATION_PYTHON_CPU_REQUEST", "50m") + os.Setenv("AUTO_INSTRUMENTATION_PYTHON_MEM_REQUEST", "32Mi") + os.Setenv("AUTO_INSTRUMENTATION_DOTNET_CPU_LIMIT", "500m") + os.Setenv("AUTO_INSTRUMENTATION_DOTNET_MEM_LIMIT", "128Mi") + os.Setenv("AUTO_INSTRUMENTATION_DOTNET_CPU_REQUEST", "50m") + os.Setenv("AUTO_INSTRUMENTATION_DOTNET_MEM_REQUEST", "128Mi") httpInst := &v1alpha1.Instrumentation{ Status: v1alpha1.InstrumentationStatus{}, @@ -51,6 +65,16 @@ func Test_getDefaultInstrumentationLinux(t *testing.T) { {Name: "OTEL_METRICS_EXPORTER", Value: "none"}, {Name: "OTEL_LOGS_EXPORTER", Value: "none"}, }, + Resources: corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("500m"), + corev1.ResourceMemory: resource.MustParse("64Mi"), + }, + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("50m"), + corev1.ResourceMemory: resource.MustParse("64Mi"), + }, + }, }, Python: v1alpha1.Python{ Image: defaultPythonInstrumentationImage, @@ -68,6 +92,16 @@ func Test_getDefaultInstrumentationLinux(t *testing.T) { {Name: "OTEL_PYTHON_CONFIGURATOR", Value: "aws_configurator"}, {Name: "OTEL_LOGS_EXPORTER", Value: "none"}, }, + Resources: corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("500m"), + corev1.ResourceMemory: resource.MustParse("32Mi"), + }, + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("50m"), + corev1.ResourceMemory: resource.MustParse("32Mi"), + }, + }, }, DotNet: v1alpha1.DotNet{ Image: defaultDotNetInstrumentationImage, @@ -85,6 +119,16 @@ func Test_getDefaultInstrumentationLinux(t *testing.T) { {Name: "OTEL_LOGS_EXPORTER", Value: "none"}, {Name: "OTEL_DOTNET_AUTO_PLUGINS", Value: "AWS.Distro.OpenTelemetry.AutoInstrumentation.Plugin, AWS.Distro.OpenTelemetry.AutoInstrumentation"}, }, + Resources: corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("500m"), + corev1.ResourceMemory: resource.MustParse("128Mi"), + }, + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("50m"), + corev1.ResourceMemory: resource.MustParse("128Mi"), + }, + }, }, }, } @@ -119,6 +163,16 @@ func Test_getDefaultInstrumentationLinux(t *testing.T) { {Name: "OTEL_METRICS_EXPORTER", Value: "none"}, {Name: "OTEL_LOGS_EXPORTER", Value: "none"}, }, + Resources: corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("500m"), + corev1.ResourceMemory: resource.MustParse("64Mi"), + }, + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("50m"), + corev1.ResourceMemory: resource.MustParse("64Mi"), + }, + }, }, Python: v1alpha1.Python{ Image: defaultPythonInstrumentationImage, @@ -136,6 +190,16 @@ func Test_getDefaultInstrumentationLinux(t *testing.T) { {Name: "OTEL_PYTHON_CONFIGURATOR", Value: "aws_configurator"}, {Name: "OTEL_LOGS_EXPORTER", Value: "none"}, }, + Resources: corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("500m"), + corev1.ResourceMemory: resource.MustParse("32Mi"), + }, + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("50m"), + corev1.ResourceMemory: resource.MustParse("32Mi"), + }, + }, }, DotNet: v1alpha1.DotNet{ Image: defaultDotNetInstrumentationImage, @@ -153,6 +217,16 @@ func Test_getDefaultInstrumentationLinux(t *testing.T) { {Name: "OTEL_LOGS_EXPORTER", Value: "none"}, {Name: "OTEL_DOTNET_AUTO_PLUGINS", Value: "AWS.Distro.OpenTelemetry.AutoInstrumentation.Plugin, AWS.Distro.OpenTelemetry.AutoInstrumentation"}, }, + Resources: corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("500m"), + corev1.ResourceMemory: resource.MustParse("128Mi"), + }, + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("50m"), + corev1.ResourceMemory: resource.MustParse("128Mi"), + }, + }, }, }, } @@ -218,6 +292,18 @@ func Test_getDefaultInstrumentationWindows(t *testing.T) { os.Setenv("AUTO_INSTRUMENTATION_JAVA", defaultJavaInstrumentationImage) os.Setenv("AUTO_INSTRUMENTATION_PYTHON", defaultPythonInstrumentationImage) os.Setenv("AUTO_INSTRUMENTATION_DOTNET", defaultDotNetInstrumentationImage) + os.Setenv("AUTO_INSTRUMENTATION_JAVA_CPU_LIMIT", "500m") + os.Setenv("AUTO_INSTRUMENTATION_JAVA_MEM_LIMIT", "64Mi") + os.Setenv("AUTO_INSTRUMENTATION_JAVA_CPU_REQUEST", "50m") + os.Setenv("AUTO_INSTRUMENTATION_JAVA_MEM_REQUEST", "64Mi") + os.Setenv("AUTO_INSTRUMENTATION_PYTHON_CPU_LIMIT", "500m") + os.Setenv("AUTO_INSTRUMENTATION_PYTHON_MEM_LIMIT", "32Mi") + os.Setenv("AUTO_INSTRUMENTATION_PYTHON_CPU_REQUEST", "50m") + os.Setenv("AUTO_INSTRUMENTATION_PYTHON_MEM_REQUEST", "32Mi") + os.Setenv("AUTO_INSTRUMENTATION_DOTNET_CPU_LIMIT", "500m") + os.Setenv("AUTO_INSTRUMENTATION_DOTNET_MEM_LIMIT", "128Mi") + os.Setenv("AUTO_INSTRUMENTATION_DOTNET_CPU_REQUEST", "50m") + os.Setenv("AUTO_INSTRUMENTATION_DOTNET_MEM_REQUEST", "128Mi") httpInst := &v1alpha1.Instrumentation{ Status: v1alpha1.InstrumentationStatus{}, @@ -250,6 +336,16 @@ func Test_getDefaultInstrumentationWindows(t *testing.T) { {Name: "OTEL_METRICS_EXPORTER", Value: "none"}, {Name: "OTEL_LOGS_EXPORTER", Value: "none"}, }, + Resources: corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("500m"), + corev1.ResourceMemory: resource.MustParse("64Mi"), + }, + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("50m"), + corev1.ResourceMemory: resource.MustParse("64Mi"), + }, + }, }, Python: v1alpha1.Python{ Image: defaultPythonInstrumentationImage, @@ -267,6 +363,16 @@ func Test_getDefaultInstrumentationWindows(t *testing.T) { {Name: "OTEL_PYTHON_CONFIGURATOR", Value: "aws_configurator"}, {Name: "OTEL_LOGS_EXPORTER", Value: "none"}, }, + Resources: corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("500m"), + corev1.ResourceMemory: resource.MustParse("32Mi"), + }, + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("50m"), + corev1.ResourceMemory: resource.MustParse("32Mi"), + }, + }, }, DotNet: v1alpha1.DotNet{ Image: defaultDotNetInstrumentationImage, @@ -284,6 +390,16 @@ func Test_getDefaultInstrumentationWindows(t *testing.T) { {Name: "OTEL_LOGS_EXPORTER", Value: "none"}, {Name: "OTEL_DOTNET_AUTO_PLUGINS", Value: "AWS.Distro.OpenTelemetry.AutoInstrumentation.Plugin, AWS.Distro.OpenTelemetry.AutoInstrumentation"}, }, + Resources: corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("500m"), + corev1.ResourceMemory: resource.MustParse("128Mi"), + }, + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("50m"), + corev1.ResourceMemory: resource.MustParse("128Mi"), + }, + }, }, }, } @@ -318,6 +434,16 @@ func Test_getDefaultInstrumentationWindows(t *testing.T) { {Name: "OTEL_METRICS_EXPORTER", Value: "none"}, {Name: "OTEL_LOGS_EXPORTER", Value: "none"}, }, + Resources: corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("500m"), + corev1.ResourceMemory: resource.MustParse("64Mi"), + }, + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("50m"), + corev1.ResourceMemory: resource.MustParse("64Mi"), + }, + }, }, Python: v1alpha1.Python{ Image: defaultPythonInstrumentationImage, @@ -335,6 +461,16 @@ func Test_getDefaultInstrumentationWindows(t *testing.T) { {Name: "OTEL_PYTHON_CONFIGURATOR", Value: "aws_configurator"}, {Name: "OTEL_LOGS_EXPORTER", Value: "none"}, }, + Resources: corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("500m"), + corev1.ResourceMemory: resource.MustParse("32Mi"), + }, + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("50m"), + corev1.ResourceMemory: resource.MustParse("32Mi"), + }, + }, }, DotNet: v1alpha1.DotNet{ Image: defaultDotNetInstrumentationImage, @@ -352,6 +488,16 @@ func Test_getDefaultInstrumentationWindows(t *testing.T) { {Name: "OTEL_LOGS_EXPORTER", Value: "none"}, {Name: "OTEL_DOTNET_AUTO_PLUGINS", Value: "AWS.Distro.OpenTelemetry.AutoInstrumentation.Plugin, AWS.Distro.OpenTelemetry.AutoInstrumentation"}, }, + Resources: corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("500m"), + corev1.ResourceMemory: resource.MustParse("128Mi"), + }, + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("50m"), + corev1.ResourceMemory: resource.MustParse("128Mi"), + }, + }, }, }, }