diff --git a/.chloggen/crds_wip.yaml b/.chloggen/crds_wip.yaml new file mode 100644 index 0000000000..7145465f4a --- /dev/null +++ b/.chloggen/crds_wip.yaml @@ -0,0 +1,16 @@ +# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' +change_type: enhancement + +# 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: webhook + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: Allow to run the mutating webhook using static configuration, without the need for CRDs. + +# One or more tracking issues related to the change +issues: [4201] + +# (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: diff --git a/.github/workflows/integration-test.yaml b/.github/workflows/integration-test.yaml new file mode 100644 index 0000000000..65f052252d --- /dev/null +++ b/.github/workflows/integration-test.yaml @@ -0,0 +1,49 @@ +name: CI +on: + push: + branches: + - main + pull_request: +jobs: + java-autoinstrumentation: + env: + KUBECONFIG: /tmp/kube-config + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: make our image + run: VERSION=dev make container + - name: make java autoinstrumentation image + run: | + cd autoinstrumentation/java && docker build -t java-autoinstrumentation:dev --build-arg version=$(cat version.txt) . + - name: Create kind cluster + uses: helm/kind-action@v1.11.0 + with: + cluster_name: kind + node_image: kindest/node:v1.27.3 + - name: Deploy certificate signing request + run: kubectl apply -f tests/integration/certs.yaml + - name: Approve our certificate signing request + run: kubectl certificate approve operator + - name: register our image + run: | + img=$(docker images | grep operator | awk '{print $1":"$2}') + docker tag $img manager:dev + kind load docker-image manager:dev --name kind + kind load docker-image java-autoinstrumentation:dev --name kind + - name: Deploy collector + run: kubectl apply -f tests/integration/collector.yaml + - name: Deploy operator + run: kubectl apply -f tests/integration/operator.yaml + - name: Sleep 10s + run: sleep 10 + - name: Deploy java app + run: kubectl apply -f tests/integration/java.yaml + - name: Sleep 20s + run: sleep 20 + - name: Check logs + run: | + COLLECTOR_POD=$(kubectl get pod -l app=collector -o jsonpath="{.items[0].metadata.name}") + LOGS=$(kubectl logs ${COLLECTOR_POD}) + echo ${LOGS} + echo ${LOGS} | grep "Starting Servlet engine" \ No newline at end of file diff --git a/internal/config/config.go b/internal/config/config.go index cd874232f4..c11a07014e 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -121,6 +121,21 @@ type Config struct { Zap ZapConfig `yaml:"zap"` // EnableWebhooks enables the webhooks used by controllers. EnableWebhooks bool `yaml:"enable-webhooks"` + // Instrumentation is the set of instrumentations to use if CRDs are not present + Instrumentation Instrumentation `yaml:"instrumentations"` + // EnableInstrumentationCRDs enables looking for instrumentation CRDs. + EnableInstrumentationCRDs bool `yaml:"enable-instrumentation-crds"` +} + +type Instrumentation struct { + ApacheHttpd *InstrumentationSpec `yaml:"apache-httpd,omitempty"` + DotNet *InstrumentationSpec `yaml:"dotnet,omitempty"` + Java *InstrumentationSpec `yaml:"java,omitempty"` + Go *InstrumentationSpec `yaml:"go,omitempty"` + NodeJS *InstrumentationSpec `yaml:"nodejs,omitempty"` + Python *InstrumentationSpec `yaml:"python,omitempty"` + Nginx *InstrumentationSpec `yaml:"nginx,omitempty"` + Sdk *InstrumentationSpec `yaml:"sdk,omitempty"` } // New constructs a new configuration. @@ -172,7 +187,8 @@ func New() Config { LevelKey: "level", LevelFormat: "uppercase", }, - EnableWebhooks: true, + EnableWebhooks: true, + EnableInstrumentationCRDs: true, } } diff --git a/internal/config/config_test.go b/internal/config/config_test.go index 6c542fe162..5b1fb3a1cf 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -36,6 +36,7 @@ func TestToStringMap(t *testing.T) { "enable-apache-httpd-instrumentation": "false", "enable-cr-metrics": "false", "enable-dot-net-auto-instrumentation": "false", + "enable-instrumentation-crds": "false", "enable-go-auto-instrumentation": "false", "enable-java-auto-instrumentation": "false", "enable-leader-election": "false", diff --git a/internal/config/instrumentation.go b/internal/config/instrumentation.go new file mode 100644 index 0000000000..c3f2b4da92 --- /dev/null +++ b/internal/config/instrumentation.go @@ -0,0 +1,412 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package config + +import ( + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" +) + +type ( + Propagator string +) + +const ( + // TraceContext represents W3C Trace Context. + TraceContext Propagator = "tracecontext" + // Baggage represents W3C Baggage. + Baggage Propagator = "baggage" + // B3 represents B3 Single. + B3 Propagator = "b3" + // B3Multi represents B3 Multi. + B3Multi Propagator = "b3multi" + // Jaeger represents Jaeger. + Jaeger Propagator = "jaeger" + // XRay represents AWS X-Ray. + XRay Propagator = "xray" + // OTTrace represents OT Trace. + OTTrace Propagator = "ottrace" + // None represents automatically configured propagator. + None Propagator = "none" +) + +// InstrumentationSpec defines the desired state of OpenTelemetry SDK and instrumentation. +type InstrumentationSpec struct { + // Exporter defines exporter configuration. + // +optional + Exporter `yaml:"exporter,omitempty"` + + // Resource defines the configuration for the resource attributes, as defined by the OpenTelemetry specification. + // +optional + Resource Resource `yaml:"resource,omitempty"` + + // Propagators defines inter-process context propagation configuration. + // Values in this list will be set in the OTEL_PROPAGATORS env var. + // Enum=tracecontext;baggage;b3;b3multi;jaeger;xray;ottrace;none + // +optional + Propagators []Propagator `yaml:"propagators,omitempty"` + + // Sampler defines sampling configuration. + // +optional + Sampler Sampler `yaml:"sampler,omitempty"` + + // Defaults defines default values for the instrumentation. + Defaults Defaults `yaml:"defaults,omitempty"` + + // Env defines common env vars. There are four layers for env vars' definitions and + // the precedence order is: `original container env vars` > `language specific env vars` > `common env vars` > `instrument spec configs' vars`. + // If the former var had been defined, then the other vars would be ignored. + // +optional + Env []corev1.EnvVar `yaml:"env,omitempty"` + + // Java defines configuration for java auto-instrumentation. + // +optional + Java Java `yaml:"java,omitempty"` + + // NodeJS defines configuration for nodejs auto-instrumentation. + // +optional + NodeJS NodeJS `yaml:"nodejs,omitempty"` + + // Python defines configuration for python auto-instrumentation. + // +optional + Python Python `yaml:"python,omitempty"` + + // DotNet defines configuration for DotNet auto-instrumentation. + // +optional + DotNet DotNet `yaml:"dotnet,omitempty"` + + // Go defines configuration for Go auto-instrumentation. + // When using Go auto-instrumentation you must provide a value for the OTEL_GO_AUTO_TARGET_EXE env var via the + // Instrumentation env vars or via the instrumentation.opentelemetry.io/otel-go-auto-target-exe pod annotation. + // Failure to set this value causes instrumentation injection to abort, leaving the original pod unchanged. + // +optional + Go Go `yaml:"go,omitempty"` + + // ApacheHttpd defines configuration for Apache HTTPD auto-instrumentation. + // +optional + ApacheHttpd ApacheHttpd `yaml:"apacheHttpd,omitempty"` + + // Nginx defines configuration for Nginx auto-instrumentation. + // +optional + Nginx Nginx `yaml:"nginx,omitempty"` + + // ImagePullPolicy + // One of Always, Never, IfNotPresent. + // Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. + // +optional + ImagePullPolicy corev1.PullPolicy `yaml:"imagePullPolicy,omitempty"` +} + +// Resource defines the configuration for the resource attributes, as defined by the OpenTelemetry specification. +// See also: https://github.com/open-telemetry/opentelemetry-specification/blob/v1.8.0/specification/overview.md#resources +type Resource struct { + // Attributes defines attributes that are added to the resource. + // For example environment: dev + // +optional + Attributes map[string]string `yaml:"resourceAttributes,omitempty"` + + // AddK8sUIDAttributes defines whether K8s UID attributes should be collected (e.g. k8s.deployment.uid). + // +optional + AddK8sUIDAttributes bool `yaml:"addK8sUIDAttributes,omitempty"` +} + +// Exporter defines OTLP exporter configuration. +type Exporter struct { + // Endpoint is address of the collector with OTLP endpoint. + // If the endpoint defines https:// scheme TLS has to be specified. + // +optional + Endpoint string `yaml:"endpoint,omitempty"` + + // TLS defines certificates for TLS. + // TLS needs to be enabled by specifying https:// scheme in the Endpoint. + TLS *TLS `yaml:"tls,omitempty"` +} + +type ( + // SamplerType represents sampler type. + SamplerType string +) + +const ( + // AlwaysOn represents AlwaysOnSampler. + AlwaysOn SamplerType = "always_on" + // AlwaysOff represents AlwaysOffSampler. + AlwaysOff SamplerType = "always_off" + // TraceIDRatio represents TraceIdRatioBased. + TraceIDRatio SamplerType = "traceidratio" + // ParentBasedAlwaysOn represents ParentBased(root=AlwaysOnSampler). + ParentBasedAlwaysOn SamplerType = "parentbased_always_on" + // ParentBasedAlwaysOff represents ParentBased(root=AlwaysOffSampler). + ParentBasedAlwaysOff SamplerType = "parentbased_always_off" + // ParentBasedTraceIDRatio represents ParentBased(root=TraceIdRatioBased). + ParentBasedTraceIDRatio SamplerType = "parentbased_traceidratio" + // JaegerRemote represents JaegerRemoteSampler. + JaegerRemote SamplerType = "jaeger_remote" + // ParentBasedJaegerRemote represents ParentBased(root=JaegerRemoteSampler). + ParentBasedJaegerRemote SamplerType = "parentbased_jaeger_remote" + // XRay represents AWS X-Ray Centralized Sampling. + XRaySampler SamplerType = "xray" +) + +// TLS defines TLS configuration for exporter. +type TLS struct { + // SecretName defines secret name that will be used to configure TLS on the exporter. + // It is user responsibility to create the secret in the namespace of the workload. + // The secret must contain client certificate (Cert) and private key (Key). + // The CA certificate might be defined in the secret or in the config map. + SecretName string `yaml:"secretName,omitempty"` + + // ConfigMapName defines configmap name with CA certificate. If it is not defined CA certificate will be + // used from the secret defined in SecretName. + ConfigMapName string `yaml:"configMapName,omitempty"` + + // CA defines the key of certificate (e.g. ca.crt) in the configmap map, secret or absolute path to a certificate. + // The absolute path can be used when certificate is already present on the workload filesystem e.g. + // /var/run/secrets/kubernetes.io/serviceaccount/service-ca.crt + CA string `yaml:"ca_file,omitempty"` + // Cert defines the key (e.g. tls.crt) of the client certificate in the secret or absolute path to a certificate. + // The absolute path can be used when certificate is already present on the workload filesystem. + Cert string `yaml:"cert_file,omitempty"` + // Key defines a key (e.g. tls.key) of the private key in the secret or absolute path to a certificate. + // The absolute path can be used when certificate is already present on the workload filesystem. + Key string `yaml:"key_file,omitempty"` +} + +// Sampler defines sampling configuration. +type Sampler struct { + // Type defines sampler type. + // The value will be set in the OTEL_TRACES_SAMPLER env var. + // The value can be for instance parentbased_always_on, parentbased_always_off, parentbased_traceidratio... + // +optional + Type SamplerType `yaml:"type,omitempty"` + + // Argument defines sampler argument. + // The value depends on the sampler type. + // For instance for parentbased_traceidratio sampler type it is a number in range [0..1] e.g. 0.25. + // The value will be set in the OTEL_TRACES_SAMPLER_ARG env var. + // +optional + Argument string `yaml:"argument,omitempty"` +} + +// Defaults defines default values for the instrumentation. +type Defaults struct { + // UseLabelsForResourceAttributes defines whether to use common labels for resource attributes: + // Note: first entry wins: + // - `app.kubernetes.io/instance` becomes `service.name` + // - `app.kubernetes.io/name` becomes `service.name` + // - `app.kubernetes.io/version` becomes `service.version` + UseLabelsForResourceAttributes bool `yaml:"useLabelsForResourceAttributes,omitempty"` +} + +// Java defines Java SDK and instrumentation configuration. +type Java struct { + // Image is a container image with javaagent auto-instrumentation JAR. + // +optional + Image string `yaml:"image,omitempty"` + + // VolumeClaimTemplate defines an ephemeral volume used for auto-instrumentation. + // If omitted, an emptyDir is used with size limit VolumeSizeLimit + VolumeClaimTemplate corev1.PersistentVolumeClaimTemplate `yaml:"volumeClaimTemplate,omitempty"` + + // VolumeSizeLimit defines size limit for volume used for auto-instrumentation. + // The default size is 200Mi. + VolumeSizeLimit *resource.Quantity `yaml:"volumeLimitSize,omitempty"` + + // Env defines java specific env vars. There are four layers for env vars' definitions and + // the precedence order is: `original container env vars` > `language specific env vars` > `common env vars` > `instrument spec configs' vars`. + // If the former var had been defined, then the other vars would be ignored. + // +optional + Env []corev1.EnvVar `yaml:"env,omitempty"` + + // Resources describes the compute resource requirements. + // +optional + Resources corev1.ResourceRequirements `yaml:"resources,omitempty"` + + // Extensions defines java specific extensions. + // All extensions are copied to a single directory; if a JAR with the same name exists, it will be overwritten. + // +optional + Extensions []Extensions `yaml:"extensions,omitempty"` +} + +type Extensions struct { + // Image is a container image with extensions auto-instrumentation JAR. + Image string `yaml:"image"` + + // Dir is a directory with extensions auto-instrumentation JAR. + Dir string `yaml:"dir"` +} + +// NodeJS defines NodeJS SDK and instrumentation configuration. +type NodeJS struct { + // Image is a container image with NodeJS SDK and auto-instrumentation. + // +optional + Image string `yaml:"image,omitempty"` + + // VolumeClaimTemplate defines an ephemeral volume used for auto-instrumentation. + // If omitted, an emptyDir is used with size limit VolumeSizeLimit + VolumeClaimTemplate corev1.PersistentVolumeClaimTemplate `yaml:"volumeClaimTemplate,omitempty"` + + // VolumeSizeLimit defines size limit for volume used for auto-instrumentation. + // The default size is 200Mi. + VolumeSizeLimit *resource.Quantity `yaml:"volumeLimitSize,omitempty"` + + // Env defines nodejs specific env vars. There are four layers for env vars' definitions and + // the precedence order is: `original container env vars` > `language specific env vars` > `common env vars` > `instrument spec configs' vars`. + // If the former var had been defined, then the other vars would be ignored. + // +optional + Env []corev1.EnvVar `yaml:"env,omitempty"` + + // Resources describes the compute resource requirements. + // +optional + Resources corev1.ResourceRequirements `yaml:"resourceRequirements,omitempty"` +} + +// Python defines Python SDK and instrumentation configuration. +type Python struct { + // Image is a container image with Python SDK and auto-instrumentation. + // +optional + Image string `yaml:"image,omitempty"` + + // VolumeClaimTemplate defines an ephemeral volume used for auto-instrumentation. + // If omitted, an emptyDir is used with size limit VolumeSizeLimit + VolumeClaimTemplate corev1.PersistentVolumeClaimTemplate `yaml:"volumeClaimTemplate,omitempty"` + + // VolumeSizeLimit defines size limit for volume used for auto-instrumentation. + // The default size is 200Mi. + VolumeSizeLimit *resource.Quantity `yaml:"volumeLimitSize,omitempty"` + + // Env defines python specific env vars. There are four layers for env vars' definitions and + // the precedence order is: `original container env vars` > `language specific env vars` > `common env vars` > `instrument spec configs' vars`. + // If the former var had been defined, then the other vars would be ignored. + // +optional + Env []corev1.EnvVar `yaml:"env,omitempty"` + + // Resources describes the compute resource requirements. + // +optional + Resources corev1.ResourceRequirements `yaml:"resourceRequirements,omitempty"` +} + +// DotNet defines DotNet SDK and instrumentation configuration. +type DotNet struct { + // Image is a container image with DotNet SDK and auto-instrumentation. + // +optional + Image string `yaml:"image,omitempty"` + + // VolumeClaimTemplate defines an ephemeral volume used for auto-instrumentation. + // If omitted, an emptyDir is used with size limit VolumeSizeLimit + VolumeClaimTemplate corev1.PersistentVolumeClaimTemplate `yaml:"volumeClaimTemplate,omitempty"` + + // VolumeSizeLimit defines size limit for volume used for auto-instrumentation. + // The default size is 200Mi. + VolumeSizeLimit *resource.Quantity `yaml:"volumeLimitSize,omitempty"` + + // Env defines DotNet specific env vars. There are four layers for env vars' definitions and + // the precedence order is: `original container env vars` > `language specific env vars` > `common env vars` > `instrument spec configs' vars`. + // If the former var had been defined, then the other vars would be ignored. + // +optional + Env []corev1.EnvVar `yaml:"env,omitempty"` + // Resources describes the compute resource requirements. + // +optional + Resources corev1.ResourceRequirements `yaml:"resourceRequirements,omitempty"` +} + +type Go struct { + // Image is a container image with Go SDK and auto-instrumentation. + // +optional + Image string `yaml:"image,omitempty"` + + // VolumeClaimTemplate defines an ephemeral volume used for auto-instrumentation. + // If omitted, an emptyDir is used with size limit VolumeSizeLimit + VolumeClaimTemplate corev1.PersistentVolumeClaimTemplate `yaml:"volumeClaimTemplate,omitempty"` + + // VolumeSizeLimit defines size limit for volume used for auto-instrumentation. + // The default size is 200Mi. + VolumeSizeLimit *resource.Quantity `yaml:"volumeLimitSize,omitempty"` + + // Env defines Go specific env vars. There are four layers for env vars' definitions and + // the precedence order is: `original container env vars` > `language specific env vars` > `common env vars` > `instrument spec configs' vars`. + // If the former var had been defined, then the other vars would be ignored. + // +optional + Env []corev1.EnvVar `yaml:"env,omitempty"` + + // Resources describes the compute resource requirements. + // +optional + Resources corev1.ResourceRequirements `yaml:"resourceRequirements,omitempty"` +} + +// ApacheHttpd defines Apache SDK and instrumentation configuration. +type ApacheHttpd struct { + // Image is a container image with Apache SDK and auto-instrumentation. + // +optional + Image string `yaml:"image,omitempty"` + + // VolumeClaimTemplate defines an ephemeral volume used for auto-instrumentation. + // If omitted, an emptyDir is used with size limit VolumeSizeLimit + VolumeClaimTemplate corev1.PersistentVolumeClaimTemplate `yaml:"volumeClaimTemplate,omitempty"` + + // VolumeSizeLimit defines size limit for volume used for auto-instrumentation. + // The default size is 200Mi. + VolumeSizeLimit *resource.Quantity `yaml:"volumeLimitSize,omitempty"` + + // Env defines Apache HTTPD specific env vars. There are four layers for env vars' definitions and + // the precedence order is: `original container env vars` > `language specific env vars` > `common env vars` > `instrument spec configs' vars`. + // If the former var had been defined, then the other vars would be ignored. + // +optional + Env []corev1.EnvVar `yaml:"env,omitempty"` + + // Attrs defines Apache HTTPD agent specific attributes. The precedence is: + // `agent default attributes` > `instrument spec attributes` . + // Attributes are documented at https://github.com/open-telemetry/opentelemetry-cpp-contrib/tree/main/instrumentation/otel-webserver-module + // +optional + Attrs []corev1.EnvVar `yaml:"attrs,omitempty"` + + // Apache HTTPD server version. One of 2.4 or 2.2. Default is 2.4 + // +optional + Version string `yaml:"version,omitempty"` + + // Location of Apache HTTPD server configuration. + // Needed only if different from default "/usr/local/apache2/conf" + // +optional + ConfigPath string `yaml:"configPath,omitempty"` + + // Resources describes the compute resource requirements. + // +optional + Resources corev1.ResourceRequirements `yaml:"resourceRequirements,omitempty"` +} + +// Nginx defines Nginx SDK and instrumentation configuration. +type Nginx struct { + // Image is a container image with Nginx SDK and auto-instrumentation. + // +optional + Image string `yaml:"image,omitempty"` + + // VolumeClaimTemplate defines an ephemeral volume used for auto-instrumentation. + // If omitted, an emptyDir is used with size limit VolumeSizeLimit + VolumeClaimTemplate corev1.PersistentVolumeClaimTemplate `yaml:"volumeClaimTemplate,omitempty"` + + // VolumeSizeLimit defines size limit for volume used for auto-instrumentation. + // The default size is 200Mi. + VolumeSizeLimit *resource.Quantity `yaml:"volumeLimitSize,omitempty"` + + // Env defines Nginx specific env vars. There are four layers for env vars' definitions and + // the precedence order is: `original container env vars` > `language specific env vars` > `common env vars` > `instrument spec configs' vars`. + // If the former var had been defined, then the other vars would be ignored. + // +optional + Env []corev1.EnvVar `yaml:"env,omitempty"` + + // Attrs defines Nginx agent specific attributes. The precedence order is: + // `agent default attributes` > `instrument spec attributes` . + // Attributes are documented at https://github.com/open-telemetry/opentelemetry-cpp-contrib/tree/main/instrumentation/otel-webserver-module + // +optional + Attrs []corev1.EnvVar `yaml:"attrs,omitempty"` + + // Location of Nginx configuration file. + // Needed only if different from default "/etx/nginx/nginx.conf" + // +optional + ConfigFile string `yaml:"configFile,omitempty"` + + // Resources describes the compute resource requirements. + // +optional + Resources corev1.ResourceRequirements `yaml:"resourceRequirements,omitempty"` +} diff --git a/internal/config/testdata/config.yaml b/internal/config/testdata/config.yaml index 05699f2998..7f9eeed173 100644 --- a/internal/config/testdata/config.yaml +++ b/internal/config/testdata/config.yaml @@ -47,3 +47,4 @@ zap: level-key: level level-format: uppercase enable-webhooks: true +enable-instrumentation-crds: true diff --git a/internal/controllers/reconcile_test.go b/internal/controllers/reconcile_test.go index 3c825b46b5..1646cb8410 100644 --- a/internal/controllers/reconcile_test.go +++ b/internal/controllers/reconcile_test.go @@ -620,6 +620,7 @@ func TestOpenTelemetryCollectorReconciler_Reconcile(t *testing.T) { PrometheusCRAvailability: prometheus.Available, TargetAllocatorConfigMapEntry: "remoteconfiguration.yaml", CollectorConfigMapEntry: "collector.yaml", + EnableInstrumentationCRDs: true, } reconciler := createTestReconciler(t, testCtx, cfg) @@ -789,6 +790,7 @@ func TestOpenTelemetryCollectorReconciler_RemoveDisabled(t *testing.T) { TargetAllocatorImage: "default-ta-allocator", OpenShiftRoutesAvailability: openshift.RoutesAvailable, PrometheusCRAvailability: prometheus.Available, + EnableInstrumentationCRDs: true, } reconciler := createTestReconciler(t, testCtx, cfg) @@ -904,6 +906,7 @@ func TestOpenTelemetryCollectorReconciler_VersionedConfigMaps(t *testing.T) { CollectorImage: "default-collector", TargetAllocatorImage: "default-ta-allocator", OpenShiftRoutesAvailability: openshift.RoutesAvailable, + EnableInstrumentationCRDs: true, } reconciler := createTestReconciler(t, testCtx, cfg) @@ -1100,6 +1103,7 @@ func TestOpAMPBridgeReconciler_Reconcile(t *testing.T) { OperatorOpAMPBridgeConfigMapEntry: "remoteconfiguration.yaml", CollectorConfigMapEntry: "collector.yaml", TargetAllocatorConfigMapEntry: "targetallocator.yaml", + EnableInstrumentationCRDs: true, } reconciler := controllers.NewOpAMPBridgeReconciler(controllers.OpAMPBridgeReconcilerParams{ Client: k8sClient, @@ -1248,6 +1252,7 @@ service: CreateRBACPermissions: autoRBAC.Available, CollectorConfigMapEntry: "collector.yaml", OperatorOpAMPBridgeConfigMapEntry: "remoteconfiguration.yaml", + EnableInstrumentationCRDs: true, } reconciler := createTestReconciler(t, testCtx, cfg) @@ -1304,6 +1309,7 @@ func TestUpgrade(t *testing.T) { TargetAllocatorImage: "default-ta-allocator", CollectorConfigMapEntry: "collector.yaml", TargetAllocatorConfigMapEntry: "remoteconfiguration.yaml", + EnableInstrumentationCRDs: true, } reconciler := createTestReconcilerWithVersion( t, testCtx, diff --git a/internal/instrumentation/podmutator.go b/internal/instrumentation/podmutator.go index 478b7face6..314564d3c7 100644 --- a/internal/instrumentation/podmutator.go +++ b/internal/instrumentation/podmutator.go @@ -414,7 +414,143 @@ func (pm *instPodMutator) Mutate(ctx context.Context, ns corev1.Namespace, pod c return modifiedPod, nil } +func ConvertConfig(cfg *config.InstrumentationSpec) *v1alpha1.InstrumentationSpec { + if cfg == nil { + return nil + } + var tls *v1alpha1.TLS + if cfg.TLS != nil { + tls = &v1alpha1.TLS{ + SecretName: cfg.TLS.SecretName, + ConfigMapName: cfg.TLS.ConfigMapName, + CA: cfg.TLS.CA, + Cert: cfg.TLS.Cert, + Key: cfg.TLS.Key, + } + } + return &v1alpha1.InstrumentationSpec{ + Exporter: v1alpha1.Exporter{ + Endpoint: cfg.Exporter.Endpoint, + TLS: tls, + }, + Resource: v1alpha1.Resource{ + Attributes: cfg.Resource.Attributes, + AddK8sUIDAttributes: cfg.Resource.AddK8sUIDAttributes, + }, + Propagators: func() []v1alpha1.Propagator { + result := make([]v1alpha1.Propagator, len(cfg.Propagators)) + for i, p := range cfg.Propagators { + result[i] = v1alpha1.Propagator(p) + } + return result + }(), + Sampler: v1alpha1.Sampler{ + Type: v1alpha1.SamplerType(cfg.Sampler.Type), + Argument: cfg.Sampler.Argument, + }, + Defaults: v1alpha1.Defaults{ + UseLabelsForResourceAttributes: cfg.Defaults.UseLabelsForResourceAttributes, + }, + Env: cfg.Env, + Java: v1alpha1.Java{ + Image: cfg.Java.Image, + VolumeClaimTemplate: cfg.Java.VolumeClaimTemplate, + VolumeSizeLimit: cfg.Java.VolumeSizeLimit, + Env: cfg.Java.Env, + Resources: cfg.Java.Resources, + Extensions: func() []v1alpha1.Extensions { + result := make([]v1alpha1.Extensions, len(cfg.Java.Extensions)) + for _, ext := range cfg.Java.Extensions { + result = append(result, v1alpha1.Extensions{ + Image: ext.Image, + Dir: ext.Dir, + }) + } + return result + }(), + }, + NodeJS: v1alpha1.NodeJS{ + Image: cfg.NodeJS.Image, + VolumeClaimTemplate: cfg.NodeJS.VolumeClaimTemplate, + VolumeSizeLimit: cfg.NodeJS.VolumeSizeLimit, + Env: cfg.NodeJS.Env, + Resources: cfg.NodeJS.Resources, + }, + Python: v1alpha1.Python{ + Image: cfg.Python.Image, + VolumeClaimTemplate: cfg.Python.VolumeClaimTemplate, + VolumeSizeLimit: cfg.Python.VolumeSizeLimit, + Env: cfg.Python.Env, + Resources: cfg.Python.Resources, + }, + DotNet: v1alpha1.DotNet{ + Image: cfg.DotNet.Image, + VolumeClaimTemplate: cfg.DotNet.VolumeClaimTemplate, + VolumeSizeLimit: cfg.DotNet.VolumeSizeLimit, + Env: cfg.DotNet.Env, + Resources: cfg.DotNet.Resources, + }, + Go: v1alpha1.Go{ + Image: cfg.Go.Image, + VolumeClaimTemplate: cfg.Go.VolumeClaimTemplate, + VolumeSizeLimit: cfg.Go.VolumeSizeLimit, + Env: cfg.Go.Env, + Resources: cfg.Go.Resources, + }, + ApacheHttpd: v1alpha1.ApacheHttpd{ + Image: cfg.ApacheHttpd.Image, + VolumeClaimTemplate: cfg.ApacheHttpd.VolumeClaimTemplate, + VolumeSizeLimit: cfg.ApacheHttpd.VolumeSizeLimit, + Env: cfg.ApacheHttpd.Env, + Attrs: cfg.ApacheHttpd.Attrs, + Version: cfg.ApacheHttpd.Version, + ConfigPath: cfg.ApacheHttpd.ConfigPath, + Resources: cfg.ApacheHttpd.Resources, + }, + Nginx: v1alpha1.Nginx{ + Image: cfg.Nginx.Image, + VolumeClaimTemplate: cfg.Nginx.VolumeClaimTemplate, + VolumeSizeLimit: cfg.Nginx.VolumeSizeLimit, + Env: cfg.Nginx.Env, + Attrs: cfg.Nginx.Attrs, + ConfigFile: cfg.Nginx.ConfigFile, + Resources: cfg.Nginx.Resources, + }, + ImagePullPolicy: cfg.ImagePullPolicy, + } +} + func (pm *instPodMutator) getInstrumentationInstance(ctx context.Context, ns corev1.Namespace, pod corev1.Pod, instAnnotation string) (*v1alpha1.Instrumentation, error) { + if !pm.config.EnableInstrumentationCRDs { + var instr *v1alpha1.InstrumentationSpec + switch instAnnotation { + case annotationInjectDotNet: + instr = ConvertConfig(pm.config.Instrumentation.DotNet) + + case annotationInjectJava: + instr = ConvertConfig(pm.config.Instrumentation.Java) + case annotationInjectNodeJS: + instr = ConvertConfig(pm.config.Instrumentation.NodeJS) + case annotationInjectGo: + instr = ConvertConfig(pm.config.Instrumentation.Go) + case annotationInjectApacheHttpd: + instr = ConvertConfig(pm.config.Instrumentation.ApacheHttpd) + case annotationInjectNginx: + instr = ConvertConfig(pm.config.Instrumentation.Nginx) + case annotationInjectPython: + instr = ConvertConfig(pm.config.Instrumentation.Python) + case annotationInjectSdk: + instr = ConvertConfig(pm.config.Instrumentation.Sdk) + default: + panic("Unknown instrumentation annotation: " + instAnnotation) + } + if instr == nil { + return nil, nil + } + return &v1alpha1.Instrumentation{ + Spec: *instr, + }, nil + } instValue := annotationValue(ns.ObjectMeta, pod.ObjectMeta, instAnnotation) if len(instValue) == 0 || strings.EqualFold(instValue, "false") { diff --git a/internal/instrumentation/podmutator_test.go b/internal/instrumentation/podmutator_test.go index e674608a2d..35ac7f340d 100644 --- a/internal/instrumentation/podmutator_test.go +++ b/internal/instrumentation/podmutator_test.go @@ -680,6 +680,7 @@ func TestMutatePod(t *testing.T) { }, }, config: config.Config{ + EnableInstrumentationCRDs: true, EnableJavaAutoInstrumentation: false, }, }, @@ -866,6 +867,7 @@ func TestMutatePod(t *testing.T) { }, }, config: config.Config{ + EnableInstrumentationCRDs: true, EnableNodeJSAutoInstrumentation: true, }, }, @@ -1140,6 +1142,7 @@ func TestMutatePod(t *testing.T) { }, }, config: config.Config{ + EnableInstrumentationCRDs: true, EnableNodeJSAutoInstrumentation: true, }, }, @@ -1428,6 +1431,7 @@ func TestMutatePod(t *testing.T) { }, }, config: config.Config{ + EnableInstrumentationCRDs: true, EnablePythonAutoInstrumentation: true, }, }, @@ -1734,6 +1738,7 @@ func TestMutatePod(t *testing.T) { }, }, config: config.Config{ + EnableInstrumentationCRDs: true, EnablePythonAutoInstrumentation: true, }, }, @@ -2028,6 +2033,7 @@ func TestMutatePod(t *testing.T) { }, }, config: config.Config{ + EnableInstrumentationCRDs: true, EnableDotNetAutoInstrumentation: true, }, }, @@ -2226,6 +2232,7 @@ func TestMutatePod(t *testing.T) { }, }, config: config.Config{ + EnableInstrumentationCRDs: true, EnableDotNetAutoInstrumentation: true, }, }, @@ -2536,6 +2543,7 @@ func TestMutatePod(t *testing.T) { }, }, config: config.Config{ + EnableInstrumentationCRDs: true, EnableDotNetAutoInstrumentation: true, }, }, @@ -2617,6 +2625,7 @@ func TestMutatePod(t *testing.T) { }, }, config: config.Config{ + EnableInstrumentationCRDs: true, EnableDotNetAutoInstrumentation: false, }, }, @@ -2795,6 +2804,7 @@ func TestMutatePod(t *testing.T) { }, }, config: config.Config{ + EnableInstrumentationCRDs: true, EnableGoAutoInstrumentation: true, }, }, @@ -2878,6 +2888,7 @@ func TestMutatePod(t *testing.T) { }, }, config: config.Config{ + EnableInstrumentationCRDs: true, EnableGoAutoInstrumentation: false, }, }, @@ -3049,6 +3060,7 @@ func TestMutatePod(t *testing.T) { }, }, config: config.Config{ + EnableInstrumentationCRDs: true, EnableApacheHttpdInstrumentation: true, }, }, @@ -3126,6 +3138,7 @@ func TestMutatePod(t *testing.T) { }, }, config: config.Config{ + EnableInstrumentationCRDs: true, EnableApacheHttpdInstrumentation: false, }, }, @@ -3306,6 +3319,7 @@ func TestMutatePod(t *testing.T) { }, }, config: config.Config{ + EnableInstrumentationCRDs: true, EnableNginxAutoInstrumentation: true, }, }, @@ -3389,6 +3403,7 @@ func TestMutatePod(t *testing.T) { }, }, config: config.Config{ + EnableInstrumentationCRDs: true, EnableMultiInstrumentation: true, EnableNodeJSAutoInstrumentation: true, EnablePythonAutoInstrumentation: true, @@ -3522,6 +3537,9 @@ func TestMutatePod(t *testing.T) { }, }, err: `instrumentations.opentelemetry.io "doesnotexists" not found`, + config: config.Config{ + EnableInstrumentationCRDs: true, + }, }, { name: "multi instrumentation for multiple containers feature gate enabled", @@ -4294,6 +4312,7 @@ func TestMutatePod(t *testing.T) { }, }, config: config.Config{ + EnableInstrumentationCRDs: true, EnableMultiInstrumentation: true, EnableJavaAutoInstrumentation: true, EnableNodeJSAutoInstrumentation: true, @@ -4454,6 +4473,7 @@ func TestMutatePod(t *testing.T) { }, }, config: config.Config{ + EnableInstrumentationCRDs: true, EnableMultiInstrumentation: false, EnableJavaAutoInstrumentation: false, EnableNodeJSAutoInstrumentation: false, @@ -4604,6 +4624,7 @@ func TestMutatePod(t *testing.T) { }, }, config: config.Config{ + EnableInstrumentationCRDs: true, EnableMultiInstrumentation: true, EnableJavaAutoInstrumentation: false, }, @@ -4802,6 +4823,7 @@ func TestMutatePod(t *testing.T) { }, }, config: config.Config{ + EnableInstrumentationCRDs: true, EnableMultiInstrumentation: true, EnableDotNetAutoInstrumentation: true, }, @@ -4905,6 +4927,7 @@ func TestMutatePod(t *testing.T) { }, }, config: config.Config{ + EnableInstrumentationCRDs: true, EnableMultiInstrumentation: true, EnableDotNetAutoInstrumentation: false, EnableNodeJSAutoInstrumentation: false, @@ -4992,6 +5015,7 @@ func TestMutatePod(t *testing.T) { require.NoError(t, err) assert.Equal(t, test.expected, pod) } else { + require.Error(t, err) assert.Contains(t, err.Error(), test.err) } }) diff --git a/internal/instrumentation/upgrade/upgrade.go b/internal/instrumentation/upgrade/upgrade.go index ce60b525ea..55aec6634c 100644 --- a/internal/instrumentation/upgrade/upgrade.go +++ b/internal/instrumentation/upgrade/upgrade.go @@ -7,13 +7,16 @@ import ( "context" "fmt" "reflect" + "strconv" "github.com/go-logr/logr" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/tools/record" "sigs.k8s.io/controller-runtime/pkg/client" "github.com/open-telemetry/opentelemetry-operator/apis/v1alpha1" "github.com/open-telemetry/opentelemetry-operator/internal/config" + "github.com/open-telemetry/opentelemetry-operator/internal/instrumentation" "github.com/open-telemetry/opentelemetry-operator/pkg/constants" ) @@ -66,13 +69,100 @@ func NewInstrumentationUpgrade(client client.Client, logger logr.Logger, recorde // +kubebuilder:rbac:groups=opentelemetry.io,resources=instrumentations,verbs=get;list;watch;update;patch // ManagedInstances upgrades managed instances by the opentelemetry-operator. -func (u *InstrumentationUpgrade) ManagedInstances(ctx context.Context) error { - u.Logger.Info("looking for managed Instrumentation instances to upgrade") +func (u *InstrumentationUpgrade) ManagedInstances(ctx context.Context, cfg config.Config) error { list := &v1alpha1.InstrumentationList{} - if err := u.Client.List(ctx, list); err != nil { - return fmt.Errorf("failed to list: %w", err) + if cfg.EnableInstrumentationCRDs { + u.Logger.Info("looking for managed Instrumentation instances to upgrade") + if err := u.Client.List(ctx, list); err != nil { + return fmt.Errorf("failed to list: %w", err) + } + } else { + list.Items = []v1alpha1.Instrumentation{} + if instr := instrumentation.ConvertConfig(cfg.Instrumentation.Java); instr != nil { + list.Items = append(list.Items, v1alpha1.Instrumentation{ + Status: v1alpha1.InstrumentationStatus{}, + TypeMeta: metav1.TypeMeta{}, + Spec: *instr, + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + "enable-java-instrumentation": strconv.FormatBool(cfg.EnableJavaAutoInstrumentation), + }, + }, + }) + } + if instr := instrumentation.ConvertConfig(cfg.Instrumentation.NodeJS); instr != nil { + list.Items = append(list.Items, v1alpha1.Instrumentation{ + Status: v1alpha1.InstrumentationStatus{}, + TypeMeta: metav1.TypeMeta{}, + Spec: *instr, + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + "enable-nodejs-instrumentation": strconv.FormatBool(cfg.EnableNodeJSAutoInstrumentation), + }, + }, + }) + } + if instr := instrumentation.ConvertConfig(cfg.Instrumentation.DotNet); instr != nil { + list.Items = append(list.Items, v1alpha1.Instrumentation{ + Status: v1alpha1.InstrumentationStatus{}, + TypeMeta: metav1.TypeMeta{}, + Spec: *instr, + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + "enable-dotnet-instrumentation": strconv.FormatBool(cfg.EnableDotNetAutoInstrumentation), + }, + }, + }) + } + if instr := instrumentation.ConvertConfig(cfg.Instrumentation.Go); instr != nil { + list.Items = append(list.Items, v1alpha1.Instrumentation{ + Status: v1alpha1.InstrumentationStatus{}, + TypeMeta: metav1.TypeMeta{}, + Spec: *instr, + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + "enable-go-instrumentation": strconv.FormatBool(cfg.EnableGoAutoInstrumentation), + }, + }, + }) + } + if instr := instrumentation.ConvertConfig(cfg.Instrumentation.Python); instr != nil { + list.Items = append(list.Items, v1alpha1.Instrumentation{ + Status: v1alpha1.InstrumentationStatus{}, + TypeMeta: metav1.TypeMeta{}, + Spec: *instr, + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + "enable-python-instrumentation": strconv.FormatBool(cfg.EnablePythonAutoInstrumentation), + }, + }, + }) + } + if instr := instrumentation.ConvertConfig(cfg.Instrumentation.ApacheHttpd); instr != nil { + list.Items = append(list.Items, v1alpha1.Instrumentation{ + Status: v1alpha1.InstrumentationStatus{}, + TypeMeta: metav1.TypeMeta{}, + Spec: *instr, + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + "enable-apache-httpd-instrumentation": strconv.FormatBool(cfg.EnableApacheHttpdInstrumentation), + }, + }, + }) + } + if instr := instrumentation.ConvertConfig(cfg.Instrumentation.Nginx); instr != nil { + list.Items = append(list.Items, v1alpha1.Instrumentation{ + Status: v1alpha1.InstrumentationStatus{}, + TypeMeta: metav1.TypeMeta{}, + Spec: *instr, + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + "enable-nginx-instrumentation": strconv.FormatBool(cfg.EnableNginxAutoInstrumentation), + }, + }, + }) + } } - for i := range list.Items { toUpgrade := list.Items[i] upgraded := u.upgrade(ctx, toUpgrade) diff --git a/internal/instrumentation/upgrade/upgrade_test.go b/internal/instrumentation/upgrade/upgrade_test.go index 172b535f39..197ae1c7d1 100644 --- a/internal/instrumentation/upgrade/upgrade_test.go +++ b/internal/instrumentation/upgrade/upgrade_test.go @@ -44,6 +44,7 @@ func TestUpgrade(t *testing.T) { } cfg := config.Config{ + EnableInstrumentationCRDs: true, AutoInstrumentationJavaImage: "java:1", AutoInstrumentationNodeJSImage: "nodejs:1", AutoInstrumentationPythonImage: "python:1", @@ -76,6 +77,7 @@ func TestUpgrade(t *testing.T) { require.NoError(t, err) cfg = config.Config{ + EnableInstrumentationCRDs: true, AutoInstrumentationJavaImage: "java:2", AutoInstrumentationNodeJSImage: "nodejs:2", AutoInstrumentationPythonImage: "python:2", @@ -93,7 +95,7 @@ func TestUpgrade(t *testing.T) { } up := NewInstrumentationUpgrade(k8sClient, ctrl.Log.WithName("instrumentation-upgrade"), &record.FakeRecorder{}, cfg) - err = up.ManagedInstances(context.Background()) + err = up.ManagedInstances(context.Background(), cfg) require.NoError(t, err) updated := v1alpha1.Instrumentation{} diff --git a/main.go b/main.go index b00c81e7a1..5b1443e3f2 100644 --- a/main.go +++ b/main.go @@ -418,7 +418,7 @@ func addDependencies(_ context.Context, mgr ctrl.Manager, cfg config.Config) err mgr.GetEventRecorderFor("opentelemetry-operator"), cfg, ) - return u.ManagedInstances(c) + return u.ManagedInstances(c, cfg) })) if err != nil { return fmt.Errorf("failed to upgrade Instrumentation instances: %w", err) diff --git a/tests/e2e-targetallocator/targetallocator-metrics/chainsaw-test.yaml b/tests/e2e-targetallocator/targetallocator-metrics/chainsaw-test.yaml index 9263263154..18c9c7ad04 100644 --- a/tests/e2e-targetallocator/targetallocator-metrics/chainsaw-test.yaml +++ b/tests/e2e-targetallocator/targetallocator-metrics/chainsaw-test.yaml @@ -52,7 +52,7 @@ spec: - assert: resource: (length($metrics[?as_string(metric."__name__") == 'otel_scope_info']) >= `0`): true - (length($metrics[?as_string(metric."__name__") == 'otelcol_exporter_sent_metric_points_total']) >= `0`): true + (length($metrics[?as_string(metric."__name__") == 'otelcol_process_cpu_seconds_total']) >= `0`): true - name: Assert Target Allocator metrics try: - command: diff --git a/tests/integration/certs.yaml b/tests/integration/certs.yaml new file mode 100644 index 0000000000..359ae5dbc0 --- /dev/null +++ b/tests/integration/certs.yaml @@ -0,0 +1,69 @@ +--- +apiVersion: certificates.k8s.io/v1 +kind: CertificateSigningRequest +metadata: + name: operator +spec: + request: "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0KTUlJQzJEQ0NBY0FDQVFBd0p6RWxNQ01HQTFVRUF3d2NiM0JsY21GMGIzSXRkMlZpYUc5dmF5NWtaV1poZFd4MApMbk4yWXpDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTXcyZGoyTlByTVFyWTRTCkF1UEEwL0lsK1BBV3N5eGR0ZzZoS3prdm81VTVVTmp5NGRYbGVuOGdVTGZFaEVwS3Z0d0JvLzQvSTY4SWZpYUkKMjNjSCt0WURYYUZEYyttOVB1bXdPNWFqbldWS2F6dEt0RGUxZ3RJL0c4NTkzSko3MHBNNHFmMlNTdXZQWmlkYwprdDBIYzZwYmJjOWRmYlBXNlZxa003UzQwM0w3Y1AxdlJncmFxVE9QUGFOdUNpMXFGVm00bGd1UTMwOTA2VnVTCnlDOHNBZlREQ1FkZ3pLQkpiT044MEtsZkNBYkJzZkU5OEFsaFFONHhkZEtuWWRpWjd2Z2ZRUGR2cmRmNWpNdFgKRkx0RDNiWUY5TFlZK2prMHM5dGhpTEhjV2gwUjVuT01nTndpTURQTW53a0k2cTBIMXhHZjFNcTk0WUx0Y3RhYwovM3lNYzRNQ0F3RUFBYUJzTUdvR0NTcUdTSWIzRFFFSkRqRmRNRnN3RGdZRFZSMFBBUUgvQkFRREFnV2dNQ0FHCkExVWRKUUVCL3dRV01CUUdDQ3NHQVFVRkJ3TUJCZ2dyQmdFRkJRY0RBakFuQmdOVkhSRUVJREFlZ2h4dmNHVnkKWVhSdmNpMTNaV0pvYjI5ckxtUmxabUYxYkhRdWMzWmpNQTBHQ1NxR1NJYjNEUUVCQ3dVQUE0SUJBUUFna3krYwpNbFZPd1JrUFpQdEE4cWxYMndTS3p1QmdrNGVFc3JwYm90akxXbC9HV2s0a1pqaHN4M2NEeDFXSnUwL3AxMHQxCmlzOE4zL0tnaVNPZjMzVHl6OGtaelBWekRmWTJoT09Semd0ZU01OG4vY1ErQk1UT0ZhQXBueThEVE80VzloL1oKSytSdzlwNVdrKzRvbHVOc2RTaEU5OG8zN3hVYVc4eEpYQUF4OFVDZ2g3MWdaNGJUNjhhU2doUktBWTAvM04rVQp6OTJYVWF6MVVSQXpXMnExRTNkUk15cnhxWHhCWDJLNjAvczlVKzlweXUzR1IvZ2JVaHJaNjNxMWpJZ0lPSFVHClp2aWpTUFdsQ05CNGlkd29tVW1Eb0syYWl6TXRTWnNETHdLTFcxS2RkaVFacjQxNWpBc0ovOWNXcW81MU9oSGQKcDZMYTFSVTQ4Ymhoclo3NAotLS0tLUVORCBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0K" + signerName: example.com/serving + usages: + - digital signature + - key encipherment + - server auth +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: certs +data: + tls.key: | + -----BEGIN PRIVATE KEY----- + MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDMNnY9jT6zEK2O + EgLjwNPyJfjwFrMsXbYOoSs5L6OVOVDY8uHV5Xp/IFC3xIRKSr7cAaP+PyOvCH4m + iNt3B/rWA12hQ3PpvT7psDuWo51lSms7SrQ3tYLSPxvOfdySe9KTOKn9kkrrz2Yn + XJLdB3OqW23PXX2z1ulapDO0uNNy+3D9b0YK2qkzjz2jbgotahVZuJYLkN9PdOlb + ksgvLAH0wwkHYMygSWzjfNCpXwgGwbHxPfAJYUDeMXXSp2HYme74H0D3b63X+YzL + VxS7Q922BfS2GPo5NLPbYYix3FodEeZzjIDcIjAzzJ8JCOqtB9cRn9TKveGC7XLW + nP98jHODAgMBAAECggEAM0IQV87WSBgNmDWJKCXEjWlenNT10FMNWYq20LnWc6RZ + WLtOWGQrZTF1UUswcX1lfs+inDS4/jxBfeaoP65vFbzuiYXm2Gq6Geo0atFStpQB + anaL2dfjqGZS0nfhH5uY9X8pnA5WY+5BE+w2qOgv7jjYzU4IOVXeaPQCToB+AsQL + XSBw+bZTyOhBrNy8gtM1wxNeKyVTbke2rI4OZybnRiRW5+1QthpdY9LtKYQPIH94 + B4tllHK7dfo5Mn47s0Mqlu+trxksbMU4ALnaSwafUQtY2JRkYRugUIKmngb4kx1w + fgOzh1nSHzpFPq5+rFT+tOj9wRvFP+mRykTkRoBJIQKBgQDxB0TZvoP6cSnOuUDR + +SFp0bBW//4gbNDzvM+a9FQfRz8bagQgjI5nlWN96jNJbTyVmXfIVbAlr3T8JVIX + MwBKkDkvbAhocek54LUXLa08gQgwz3XJX4WxX5lrGc1YhQcnOFmPGUBP1tLwEAx2 + KQgjnPDyUe7aMsNkIYgIwAxBqQKBgQDY5cQdZRfxeKlOlwlPvcQB/bpaZVA5LhmQ + hfHZRJiaPAp+prohJVSQ/UtjLHYnS1NdiH41Zi/I6L3rfRlPumC/q19p7ScJjAKd + 9XdlZvrIjb+Ud9h+DBMFp/axDUfEpou7yPAAn1kff6xU2h1VMP6gaLRyFFCQTCrn + BqYe3YvfSwKBgQCNXm0Upbi1IMCbvm51eYEOlu2t6ZH9JLXd7+V4hkv82IX8J09q + Y+Z2fNmRFdek/owlVpE6EIAzaljcN2uRrdlC4pqX5O59jCp2RwUQJjtQnIHYVyZH + yV4Z7e+HMOgPPl82ssdctjvRWDf6k/8rIt/iO3/bMRE+K74Msdoe/71wmQKBgGdN + 2ABgG+1ImOrziN3P9kE0hcN0KadyS37ILQ5cW4pqOl1kL5aF3ydHXNaZYJUKjWQp + FGN+jhfUslAsvxd4H4hqqQEckNE9PCnbtcg4Kg3HZY3jHtu6CH1TKG3fc2U4JamE + 5LqHKr2T45JuaDYhJcVk2TzUbCKuBGkQg6KDxpDNAoGBAIjjqCojvwrJCS+LywEv + F3bqXzIvXeDjbwDOe/mQhwBLzvpsHqTkZZWuy7eOuQsOFgJLz0Az0LNRUN4RV6N7 + 2TpKG+XuegomTsDjDkunKzewSaKmWHYOxo5jy52STmtv72jW4YhjRLYZ3MMedMpB + jWuuCAvDcrNaABMyOGHzZraD + -----END PRIVATE KEY----- + tls.crt: | + -----BEGIN CERTIFICATE----- + MIIDWjCCAkKgAwIBAgIUdU5Qo8rswpglH+/B7g4/7kQRLAkwDQYJKoZIhvcNAQEL + BQAwJzElMCMGA1UEAwwcb3BlcmF0b3Itd2ViaG9vay5kZWZhdWx0LnN2YzAgFw0y + NDEyMjcyMDE3MDFaGA8yMDUyMDUxNDIwMTcwMVowJzElMCMGA1UEAwwcb3BlcmF0 + b3Itd2ViaG9vay5kZWZhdWx0LnN2YzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC + AQoCggEBAMw2dj2NPrMQrY4SAuPA0/Il+PAWsyxdtg6hKzkvo5U5UNjy4dXlen8g + ULfEhEpKvtwBo/4/I68IfiaI23cH+tYDXaFDc+m9PumwO5ajnWVKaztKtDe1gtI/ + G8593JJ70pM4qf2SSuvPZidckt0Hc6pbbc9dfbPW6VqkM7S403L7cP1vRgraqTOP + PaNuCi1qFVm4lguQ30906VuSyC8sAfTDCQdgzKBJbON80KlfCAbBsfE98AlhQN4x + ddKnYdiZ7vgfQPdvrdf5jMtXFLtD3bYF9LYY+jk0s9thiLHcWh0R5nOMgNwiMDPM + nwkI6q0H1xGf1Mq94YLtctac/3yMc4MCAwEAAaN8MHowDgYDVR0PAQH/BAQDAgWg + MCAGA1UdJQEB/wQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAnBgNVHREEIDAeghxv + cGVyYXRvci13ZWJob29rLmRlZmF1bHQuc3ZjMB0GA1UdDgQWBBTeVi00CIUEE+Bk + kEiDl25qjVcfGTANBgkqhkiG9w0BAQsFAAOCAQEAWYfXUwV9wgJhfPIZuI9puX59 + fXlzksS/X2EE9C9gDg5zuPLZ8MmfBglFR+xBO3PXLBKxCU0U2nwZwuKT1qbTXcHf + kPywNOnMDAvbfO3I8zg+4eNeMM5WWrrL7JA6L6kSMY3wk1VPriRTajrmJP53T9rI + 1XZLRM6C0xl34gniOqRK+CnmpYUw0yQUi0neeMgQFmhzClaafdNWd6aerBQik1jg + kn4iNr5FKfmDHNr/WrmcDJ8GTCgKU4R+f4zFFhgO7dHpUs5zD4szirq6n2ayEd8b + aSU0+wL2C4Kd72AYDHrkaG2Qi19xCZJDIFqT14m5Rexpbx4i+9E6LgonqX0g4w== + -----END CERTIFICATE----- + diff --git a/tests/integration/collector.yaml b/tests/integration/collector.yaml new file mode 100644 index 0000000000..38557086a1 --- /dev/null +++ b/tests/integration/collector.yaml @@ -0,0 +1,80 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: collector +spec: + replicas: 1 + selector: + matchLabels: + app: collector + template: + metadata: + name: collector + labels: + app: collector + spec: + automountServiceAccountToken: false + containers: + - image: otel/opentelemetry-collector-contrib:latest + name: collector + imagePullPolicy: IfNotPresent + volumeMounts: + - name: config-volume + mountPath: /etc/otelcol-contrib/config.yaml + subPath: config.yaml + ports: + - containerPort: 4317 + name: otlp + - containerPort: 4318 + name: otlphttp + volumes: + - name: config-volume + configMap: + name: collector-config +--- +apiVersion: v1 +kind: Service +metadata: + name: collector + namespace: default +spec: + ports: + - port: 4317 + protocol: TCP + targetPort: otlp + name: otlp + - port: 4318 + protocol: TCP + targetPort: otlphttp + name: otlphttp + selector: + app: collector +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: collector-config + namespace: default +data: + config.yaml: | + receivers: + otlp: + protocols: + grpc: + endpoint: "0.0.0.0:4317" + http: + endpoint: "0.0.0.0:4318" + exporters: + debug: + verbosity: detailed + service: + pipelines: + metrics: + receivers: [otlp] + exporters: [debug] + traces: + receivers: [otlp] + exporters: [debug] + logs: + receivers: [otlp] + exporters: [debug] \ No newline at end of file diff --git a/tests/integration/java.yaml b/tests/integration/java.yaml new file mode 100644 index 0000000000..a39e03dd81 --- /dev/null +++ b/tests/integration/java.yaml @@ -0,0 +1,22 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: java-app +spec: + replicas: 1 + selector: + matchLabels: + app: java-app + template: + metadata: + name: java-app + labels: + app: java-app + annotations: + instrumentation.opentelemetry.io/inject-java: "true" + spec: + automountServiceAccountToken: false + containers: + - image: tomcat:latest + name: java-app + imagePullPolicy: IfNotPresent diff --git a/tests/integration/operator.yaml b/tests/integration/operator.yaml new file mode 100644 index 0000000000..a68390c643 --- /dev/null +++ b/tests/integration/operator.yaml @@ -0,0 +1,166 @@ +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: manager-config + namespace: default +data: + config.yaml: | + ignore-missing-collector-crds: true + enable-instrumentation-crds: false + enable-multi-instrumentation: false + instrumentations: + java: + exporter: + endpoint: http://collector.default.svc:4318 + propagators: + - tracecontext + - baggage + - b3 + java: + image: "java-autoinstrumentation:dev" +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: operator +spec: + replicas: 1 + selector: + matchLabels: + app: operator + template: + metadata: + name: operator + labels: + app: operator + spec: + serviceAccountName: operator + containers: + - image: manager:dev + name: operator + imagePullPolicy: IfNotPresent + env: + - name: KUBERNETES_MASTER + value: kube-apiserver-kind-control-plane + ports: + - containerPort: 9443 + name: webhook-server + volumeMounts: + - mountPath: /tmp/k8s-webhook-server/serving-certs + name: certs + - mountPath: /etc/config.yaml + name: config + subPath: config.yaml + command: + - /manager + - --config-file + - /etc/config.yaml + volumes: + - name: certs + configMap: + name: certs + - name: config + configMap: + name: manager-config +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: operator +rules: + - apiGroups: [""] + resources: + - configmaps + - persistentvolumeclaims + - persistentvolumes + - pods + - serviceaccounts + - services + - namespaces + verbs: ["get", "watch", "list"] + - apiGroups: [ "" ] + resources: + - events + verbs: [ "get", "watch", "list", "create", "patch" ] + - apiGroups: ["apps", "extensions"] + resources: + - daemonsets + - deployments + - statefulsets + - replicasets + verbs: ["get", "watch", "list"] + - apiGroups: [ "autoscaling" ] + resources: + - horizontalpodautoscalers + verbs: [ "get", "watch", "list" ] + - apiGroups: [ "policy" ] + resources: + - poddisruptionbudgets + verbs: [ "get", "watch", "list" ] + - apiGroups: ["networking.k8s.io"] + resources: + - ingresses + verbs: [ "get", "watch", "list" ] +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: operator +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: watch-deployments +roleRef: + kind: ClusterRole + name: operator + apiGroup: rbac.authorization.k8s.io +subjects: + - kind: ServiceAccount + name: operator + namespace: default +--- +apiVersion: v1 +kind: Service +metadata: + name: operator-webhook + namespace: default +spec: + ports: + - port: 443 + protocol: TCP + targetPort: webhook-server + selector: + app: operator +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: MutatingWebhookConfiguration +metadata: + labels: + app.kubernetes.io/component: webhook + name: webhook-mutation +webhooks: + - admissionReviewVersions: + - v1 + clientConfig: + caBundle: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURXakNDQWtLZ0F3SUJBZ0lVZFU1UW84cnN3cGdsSCsvQjdnNC83a1FSTEFrd0RRWUpLb1pJaHZjTkFRRUwKQlFBd0p6RWxNQ01HQTFVRUF3d2NiM0JsY21GMGIzSXRkMlZpYUc5dmF5NWtaV1poZFd4MExuTjJZekFnRncweQpOREV5TWpjeU1ERTNNREZhR0E4eU1EVXlNRFV4TkRJd01UY3dNVm93SnpFbE1DTUdBMVVFQXd3Y2IzQmxjbUYwCmIzSXRkMlZpYUc5dmF5NWtaV1poZFd4MExuTjJZekNDQVNJd0RRWUpLb1pJaHZjTkFRRUJCUUFEZ2dFUEFEQ0MKQVFvQ2dnRUJBTXcyZGoyTlByTVFyWTRTQXVQQTAvSWwrUEFXc3l4ZHRnNmhLemt2bzVVNVVOank0ZFhsZW44ZwpVTGZFaEVwS3Z0d0JvLzQvSTY4SWZpYUkyM2NIK3RZRFhhRkRjK205UHVtd081YWpuV1ZLYXp0S3REZTFndEkvCkc4NTkzSko3MHBNNHFmMlNTdXZQWmlkY2t0MEhjNnBiYmM5ZGZiUFc2VnFrTTdTNDAzTDdjUDF2UmdyYXFUT1AKUGFOdUNpMXFGVm00bGd1UTMwOTA2VnVTeUM4c0FmVERDUWRnektCSmJPTjgwS2xmQ0FiQnNmRTk4QWxoUU40eApkZEtuWWRpWjd2Z2ZRUGR2cmRmNWpNdFhGTHREM2JZRjlMWVkramswczl0aGlMSGNXaDBSNW5PTWdOd2lNRFBNCm53a0k2cTBIMXhHZjFNcTk0WUx0Y3RhYy8zeU1jNE1DQXdFQUFhTjhNSG93RGdZRFZSMFBBUUgvQkFRREFnV2cKTUNBR0ExVWRKUUVCL3dRV01CUUdDQ3NHQVFVRkJ3TUJCZ2dyQmdFRkJRY0RBakFuQmdOVkhSRUVJREFlZ2h4dgpjR1Z5WVhSdmNpMTNaV0pvYjI5ckxtUmxabUYxYkhRdWMzWmpNQjBHQTFVZERnUVdCQlRlVmkwMENJVUVFK0JrCmtFaURsMjVxalZjZkdUQU5CZ2txaGtpRzl3MEJBUXNGQUFPQ0FRRUFXWWZYVXdWOXdnSmhmUEladUk5cHVYNTkKZlhsemtzUy9YMkVFOUM5Z0RnNXp1UExaOE1tZkJnbEZSK3hCTzNQWExCS3hDVTBVMm53Wnd1S1QxcWJUWGNIZgprUHl3Tk9uTURBdmJmTzNJOHpnKzRlTmVNTTVXV3JyTDdKQTZMNmtTTVkzd2sxVlByaVJUYWpybUpQNTNUOXJJCjFYWkxSTTZDMHhsMzRnbmlPcVJLK0NubXBZVXcweVFVaTBuZWVNZ1FGbWh6Q2xhYWZkTldkNmFlckJRaWsxamcKa240aU5yNUZLZm1ESE5yL1dybWNESjhHVENnS1U0UitmNHpGRmhnTzdkSHBVczV6RDRzemlycTZuMmF5RWQ4YgphU1UwK3dMMkM0S2Q3MkFZREhya2FHMlFpMTl4Q1pKRElGcVQxNG01UmV4cGJ4NGkrOUU2TGdvbnFYMGc0dz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K + service: + name: operator-webhook + namespace: default + path: /mutate-v1-pod + port: 443 + failurePolicy: Ignore + name: mpod.kb.io + rules: + - apiGroups: + - "" + apiVersions: + - v1 + operations: + - CREATE + resources: + - pods + scope: Namespaced + sideEffects: None + timeoutSeconds: 30 \ No newline at end of file