From d3488458cf4185f4a6c29cc5ea99eecdbe2f0e83 Mon Sep 17 00:00:00 2001 From: Ilia Petrov Date: Fri, 17 Apr 2026 12:15:42 +0300 Subject: [PATCH 1/3] feat: move apis to a separate sub-module Signed-off-by: Ilia Petrov --- apis/go.mod | 3 +++ go.mod | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 apis/go.mod diff --git a/apis/go.mod b/apis/go.mod new file mode 100644 index 0000000000..612531e7c0 --- /dev/null +++ b/apis/go.mod @@ -0,0 +1,3 @@ +module github.com/open-telemetry/opentelemetry-operator/apis + +go 1.24.13 diff --git a/go.mod b/go.mod index b511b33491..9c432ca4d1 100644 --- a/go.mod +++ b/go.mod @@ -26,6 +26,7 @@ require ( github.com/oklog/run v1.2.0 github.com/oklog/ulid v1.3.1 github.com/open-telemetry/opamp-go v0.15.0 + github.com/open-telemetry/opentelemetry-operator/apis v0.148.0-unpublished github.com/openshift/api v0.0.0-20260130140113-71e91db96ffc github.com/operator-framework/api v0.42.0 github.com/operator-framework/operator-lib v0.19.0 @@ -40,7 +41,7 @@ require ( github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/featuregate v1.55.0 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.68.0 - go.opentelemetry.io/contrib/otelconf v0.23.0 + go.opentelemetry.io/contrib/otelconf v0.23.0 // indirect go.opentelemetry.io/otel v1.43.0 go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.43.0 go.opentelemetry.io/otel/exporters/prometheus v0.65.0 @@ -63,6 +64,8 @@ require ( sigs.k8s.io/yaml v1.6.0 ) +replace github.com/open-telemetry/opentelemetry-operator/apis v0.148.0-unpublished => ./apis + require ( cel.dev/expr v0.25.1 // indirect cloud.google.com/go/auth v0.18.1 // indirect From 1489ca3dea8dbef6d7a9d1a9350ffbb5c4fd33e9 Mon Sep 17 00:00:00 2001 From: Ilia Petrov Date: Sat, 18 Apr 2026 01:11:35 +0300 Subject: [PATCH 2/3] feat: add apihelpers package Signed-off-by: Ilia Petrov --- apis/go.mod | 71 ++- apis/go.sum | 162 ++++++ apis/v1alpha1/convert.go | 7 +- apis/v1beta1/config.go | 543 +----------------- apis/v1beta1/zz_generated.deepcopy.go | 15 - go.mod | 2 +- internal/apihelpers/v1beta1/config.go | 542 +++++++++++++++++ .../apihelpers}/v1beta1/config_test.go | 441 +++++++------- .../apihelpers}/v1beta1/helpers.go | 4 +- .../apihelpers}/v1beta1/helpers_test.go | 2 +- .../apihelpers}/v1beta1/metrics.go | 20 +- .../apihelpers}/v1beta1/metrics_test.go | 108 ++-- .../v1beta1/targetallocator_rbac.go | 2 +- .../manifests/collector/config_replace.go | 3 +- internal/manifests/collector/configmap.go | 3 +- internal/manifests/collector/container.go | 13 +- internal/manifests/collector/ingress.go | 3 +- internal/manifests/collector/podmonitor.go | 3 +- internal/manifests/collector/rbac.go | 7 +- internal/manifests/collector/service.go | 7 +- .../manifests/collector/servicemonitor.go | 3 +- internal/manifests/collector/volume.go | 3 +- .../manifests/targetallocator/configmap.go | 3 +- .../targetallocator/configmap_test.go | 3 +- internal/webhook/collector_webhook.go | 21 +- internal/webhook/collector_webhook_test.go | 3 +- internal/webhook/targetallocator_webhook.go | 3 +- main.go | 7 +- pkg/collector/upgrade/v0_111_0.go | 3 +- pkg/collector/upgrade/v0_122_0.go | 9 +- pkg/sidecar/pod_test.go | 5 +- 31 files changed, 1132 insertions(+), 889 deletions(-) create mode 100644 apis/go.sum create mode 100644 internal/apihelpers/v1beta1/config.go rename {apis => internal/apihelpers}/v1beta1/config_test.go (76%) rename {apis => internal/apihelpers}/v1beta1/helpers.go (98%) rename {apis => internal/apihelpers}/v1beta1/helpers_test.go (99%) rename {apis => internal/apihelpers}/v1beta1/metrics.go (89%) rename {apis => internal/apihelpers}/v1beta1/metrics_test.go (87%) rename {apis => internal/apihelpers}/v1beta1/targetallocator_rbac.go (98%) diff --git a/apis/go.mod b/apis/go.mod index 612531e7c0..da8977d61c 100644 --- a/apis/go.mod +++ b/apis/go.mod @@ -1,3 +1,72 @@ module github.com/open-telemetry/opentelemetry-operator/apis -go 1.24.13 +go 1.25.0 + +require ( + github.com/goccy/go-yaml v1.19.2 + github.com/stretchr/testify v1.11.1 + go.opentelemetry.io/contrib/otelconf v0.23.0 + k8s.io/api v0.35.4 + k8s.io/apimachinery v0.35.4 + sigs.k8s.io/controller-runtime v0.23.3 +) + +require ( + github.com/beorn7/perks v1.0.1 // indirect + github.com/cenkalti/backoff/v5 v5.0.3 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/fxamacker/cbor/v2 v2.9.0 // indirect + github.com/go-logr/logr v1.4.3 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/prometheus/client_golang v1.23.2 // indirect + github.com/prometheus/client_model v0.6.2 // indirect + github.com/prometheus/common v0.67.5 // indirect + github.com/prometheus/otlptranslator v1.0.0 // indirect + github.com/prometheus/procfs v0.20.1 // indirect + github.com/x448/float16 v0.8.4 // indirect + go.opentelemetry.io/auto/sdk v1.2.1 // indirect + go.opentelemetry.io/otel v1.43.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.19.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.19.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.43.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.43.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.43.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0 // indirect + go.opentelemetry.io/otel/exporters/prometheus v0.65.0 // indirect + go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.19.0 // indirect + go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.43.0 // indirect + go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.43.0 // indirect + go.opentelemetry.io/otel/log v0.19.0 // indirect + go.opentelemetry.io/otel/metric v1.43.0 // indirect + go.opentelemetry.io/otel/sdk v1.43.0 // indirect + go.opentelemetry.io/otel/sdk/log v0.19.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.43.0 // indirect + go.opentelemetry.io/otel/trace v1.43.0 // indirect + go.opentelemetry.io/proto/otlp v1.10.0 // indirect + go.yaml.in/yaml/v2 v2.4.4 // indirect + go.yaml.in/yaml/v3 v3.0.4 // indirect + golang.org/x/net v0.52.0 // indirect + golang.org/x/sys v0.42.0 // indirect + golang.org/x/text v0.35.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20260406210006-6f92a3bedf2d // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260406210006-6f92a3bedf2d // indirect + google.golang.org/grpc v1.80.0 // indirect + google.golang.org/protobuf v1.36.11 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/klog/v2 v2.130.1 // indirect + k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 // indirect + k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 // indirect + sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect + sigs.k8s.io/randfill v1.0.0 // indirect + sigs.k8s.io/structured-merge-diff/v6 v6.3.2-0.20260122202528-d9cc6641c482 // indirect +) diff --git a/apis/go.sum b/apis/go.sum new file mode 100644 index 0000000000..2fc0bbcf2a --- /dev/null +++ b/apis/go.sum @@ -0,0 +1,162 @@ +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= +github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM= +github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM= +github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 h1:HWRh5R2+9EifMyIHV7ZV+MIZqgz+PMpZ14Jynv3O2Zs= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0/go.mod h1:JfhWUomR1baixubs02l85lZYYOm7LV6om4ceouMv45c= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= +github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= +github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o= +github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= +github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= +github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= +github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4= +github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw= +github.com/prometheus/otlptranslator v1.0.0 h1:s0LJW/iN9dkIH+EnhiD3BlkkP5QVIUVEoIwkU+A6qos= +github.com/prometheus/otlptranslator v1.0.0/go.mod h1:vRYWnXvI6aWGpsdY/mOT/cbeVRBlPWtBNDb7kGR3uKM= +github.com/prometheus/procfs v0.20.1 h1:XwbrGOIplXW/AU3YhIhLODXMJYyC1isLFfYCsTEycfc= +github.com/prometheus/procfs v0.20.1/go.mod h1:o9EMBZGRyvDrSPH1RqdxhojkuXstoe4UlK79eF5TGGo= +github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= +github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= +github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY= +github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= +go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= +go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= +go.opentelemetry.io/contrib/otelconf v0.23.0 h1:s3C7KdMYiutf4rC8hKFA0WOIDG+gIru8ajjQKS59ir8= +go.opentelemetry.io/contrib/otelconf v0.23.0/go.mod h1:0kN2tcccZS82e7IZlo045gkcL8/8dup1k25sf9ypGxM= +go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I= +go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.19.0 h1:Dn8rkudDzY6KV9dr/D/bTUuWgqDf9xe0rr4G2elrn0Y= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.19.0/go.mod h1:gMk9F0xDgyN9M/3Ed5Y1wKcx/9mlU91NXY2SNq7RQuU= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.19.0 h1:HIBTQ3VO5aupLKjC90JgMqpezVXwFuq6Ryjn0/izoag= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.19.0/go.mod h1:ji9vId85hMxqfvICA0Jt8JqEdrXaAkcpkI9HPXya0ro= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.43.0 h1:8UQVDcZxOJLtX6gxtDt3vY2WTgvZqMQRzjsqiIHQdkc= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.43.0/go.mod h1:2lmweYCiHYpEjQ/lSJBYhj9jP1zvCvQW4BqL9dnT7FQ= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.43.0 h1:w1K+pCJoPpQifuVpsKamUdn9U0zM3xUziVOqsGksUrY= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.43.0/go.mod h1:HBy4BjzgVE8139ieRI75oXm3EcDN+6GhD88JT1Kjvxg= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0 h1:88Y4s2C8oTui1LGM6bTWkw0ICGcOLCAI5l6zsD1j20k= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0/go.mod h1:Vl1/iaggsuRlrHf/hfPJPvVag77kKyvrLeD10kpMl+A= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.43.0 h1:RAE+JPfvEmvy+0LzyUA25/SGawPwIUbZ6u0Wug54sLc= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.43.0/go.mod h1:AGmbycVGEsRx9mXMZ75CsOyhSP6MFIcj/6dnG+vhVjk= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0 h1:3iZJKlCZufyRzPzlQhUIWVmfltrXuGyfjREgGP3UUjc= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0/go.mod h1:/G+nUPfhq2e+qiXMGxMwumDrP5jtzU+mWN7/sjT2rak= +go.opentelemetry.io/otel/exporters/prometheus v0.65.0 h1:jOveH/b4lU9HT7y+Gfamf18BqlOuz2PWEvs8yM7Q6XE= +go.opentelemetry.io/otel/exporters/prometheus v0.65.0/go.mod h1:i1P8pcumauPtUI4YNopea1dhzEMuEqWP1xoUZDylLHo= +go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.19.0 h1:GJkybS+crDMdExT/BUNCEgfrmfboztcS6PhvSo88HKM= +go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.19.0/go.mod h1:NuAyxRYIG2lKX3YQkB+83StTxM7s52PUUkRRiC0wnYI= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.43.0 h1:TC+BewnDpeiAmcscXbGMfxkO+mwYUwE/VySwvw88PfA= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.43.0/go.mod h1:J/ZyF4vfPwsSr9xJSPyQ4LqtcTPULFR64KwTikGLe+A= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.43.0 h1:mS47AX77OtFfKG4vtp+84kuGSFZHTyxtXIN269vChY0= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.43.0/go.mod h1:PJnsC41lAGncJlPUniSwM81gc80GkgWJWr3cu2nKEtU= +go.opentelemetry.io/otel/log v0.19.0 h1:KUZs/GOsw79TBBMfDWsXS+KZ4g2Ckzksd1ymzsIEbo4= +go.opentelemetry.io/otel/log v0.19.0/go.mod h1:5DQYeGmxVIr4n0/BcJvF4upsraHjg6vudJJpnkL6Ipk= +go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM= +go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY= +go.opentelemetry.io/otel/sdk v1.43.0 h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg= +go.opentelemetry.io/otel/sdk v1.43.0/go.mod h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg= +go.opentelemetry.io/otel/sdk/log v0.19.0 h1:scYVLqT22D2gqXItnWiocLUKGH9yvkkeql5dBDiXyko= +go.opentelemetry.io/otel/sdk/log v0.19.0/go.mod h1:vFBowwXGLlW9AvpuF7bMgnNI95LiW10szrOdvzBHlAg= +go.opentelemetry.io/otel/sdk/log/logtest v0.19.0 h1:BEbF7ZBB6qQloV/Ub1+3NQoOUnVtcGkU3XX4Ws3GQfk= +go.opentelemetry.io/otel/sdk/log/logtest v0.19.0/go.mod h1:Lua81/3yM0wOmoHTokLj9y9ADeA02v1naRrVrkAZuKk= +go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfCGLEo89fDkw= +go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A= +go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A= +go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0= +go.opentelemetry.io/proto/otlp v1.10.0 h1:IQRWgT5srOCYfiWnpqUYz9CVmbO8bFmKcwYxpuCSL2g= +go.opentelemetry.io/proto/otlp v1.10.0/go.mod h1:/CV4QoCR/S9yaPj8utp3lvQPoqMtxXdzn7ozvvozVqk= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ= +go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ= +go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= +golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0= +golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw= +golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= +golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8= +golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA= +gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= +gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= +google.golang.org/genproto/googleapis/api v0.0.0-20260406210006-6f92a3bedf2d h1:/aDRtSZJjyLQzm75d+a1wOJaqyKBMvIAfeQmoa3ORiI= +google.golang.org/genproto/googleapis/api v0.0.0-20260406210006-6f92a3bedf2d/go.mod h1:etfGUgejTiadZAUaEP14NP97xi1RGeawqkjDARA/UOs= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260406210006-6f92a3bedf2d h1:wT2n40TBqFY6wiwazVK9/iTWbsQrgk5ZfCSVFLO9LQA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260406210006-6f92a3bedf2d/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= +google.golang.org/grpc v1.80.0 h1:Xr6m2WmWZLETvUNvIUmeD5OAagMw3FiKmMlTdViWsHM= +google.golang.org/grpc v1.80.0/go.mod h1:ho/dLnxwi3EDJA4Zghp7k2Ec1+c2jqup0bFkw07bwF4= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +k8s.io/api v0.35.4 h1:P7nFYKl5vo9AGUp1Z+Pmd3p2tA7bX2wbFWCvDeRv988= +k8s.io/api v0.35.4/go.mod h1:yl4lqySWOgYJJf9RERXKUwE9g2y+CkuwG+xmcOK8wXU= +k8s.io/apimachinery v0.35.4 h1:xtdom9RG7e+yDp71uoXoJDWEE2eOiHgeO4GdBzwWpds= +k8s.io/apimachinery v0.35.4/go.mod h1:NNi1taPOpep0jOj+oRha3mBJPqvi0hGdaV8TCqGQ+cc= +k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= +k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= +k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 h1:Y3gxNAuB0OBLImH611+UDZcmKS3g6CthxToOb37KgwE= +k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 h1:SjGebBtkBqHFOli+05xYbK8YF1Dzkbzn+gDM4X9T4Ck= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/controller-runtime v0.23.3 h1:VjB/vhoPoA9l1kEKZHBMnQF33tdCLQKJtydy4iqwZ80= +sigs.k8s.io/controller-runtime v0.23.3/go.mod h1:B6COOxKptp+YaUT5q4l6LqUJTRpizbgf9KSRNdQGns0= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= +sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= +sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= +sigs.k8s.io/structured-merge-diff/v6 v6.3.2-0.20260122202528-d9cc6641c482 h1:2WOzJpHUBVrrkDjU4KBT8n5LDcj824eX0I5UKcgeRUs= +sigs.k8s.io/structured-merge-diff/v6 v6.3.2-0.20260122202528-d9cc6641c482/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= +sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= +sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/apis/v1alpha1/convert.go b/apis/v1alpha1/convert.go index b6575958e5..3e29a9b65f 100644 --- a/apis/v1alpha1/convert.go +++ b/apis/v1alpha1/convert.go @@ -4,6 +4,7 @@ package v1alpha1 import ( + "bytes" "fmt" go_yaml "github.com/goccy/go-yaml" @@ -301,10 +302,12 @@ func tov1alpha1Ports(in []v1beta1.PortsSpec) []PortsSpec { func tov1alpha1(in v1beta1.OpenTelemetryCollector) (*OpenTelemetryCollector, error) { c := in.DeepCopy() - configYaml, err := c.Spec.Config.Yaml() - if err != nil { + var configBuf bytes.Buffer + yamlEncoder := go_yaml.NewEncoder(&configBuf, go_yaml.IndentSequence(true), go_yaml.AutoInt()) + if err := yamlEncoder.Encode(&c.Spec.Config); err != nil { return nil, err } + configYaml := configBuf.String() return &OpenTelemetryCollector{ ObjectMeta: c.ObjectMeta, diff --git a/apis/v1beta1/config.go b/apis/v1beta1/config.go index a37390ce60..9485cef90a 100644 --- a/apis/v1beta1/config.go +++ b/apis/v1beta1/config.go @@ -4,48 +4,12 @@ package v1beta1 import ( - "bytes" "encoding/json" - "fmt" "maps" - "math" - "slices" - "strings" - "dario.cat/mergo" - "github.com/go-logr/logr" - go_yaml "github.com/goccy/go-yaml" otelConfig "go.opentelemetry.io/contrib/otelconf/v0.3.0" - corev1 "k8s.io/api/core/v1" - rbacv1 "k8s.io/api/rbac/v1" - - "github.com/open-telemetry/opentelemetry-operator/internal/components" - "github.com/open-telemetry/opentelemetry-operator/internal/components/exporters" - "github.com/open-telemetry/opentelemetry-operator/internal/components/extensions" - "github.com/open-telemetry/opentelemetry-operator/internal/components/processors" - "github.com/open-telemetry/opentelemetry-operator/internal/components/receivers" ) -type ComponentKind int - -const ( - KindReceiver ComponentKind = iota - KindExporter - KindProcessor - KindExtension -) - -func (c ComponentKind) String() string { - return [...]string{"receiver", "exporter", "processor", "extension"}[c] -} - -// EventInfo represents an event to be recorded. -type EventInfo struct { - Type string - Reason string - Message string -} - // AnyConfig represent parts of the config. type AnyConfig struct { Object map[string]any `json:"-" yaml:",inline"` @@ -130,347 +94,7 @@ type Config struct { Service Service `json:"service" yaml:"service"` } -// GetEnabledComponents constructs a list of enabled components by component type. -func (c *Config) GetEnabledComponents() map[ComponentKind]map[string]any { - toReturn := map[ComponentKind]map[string]any{ - KindReceiver: {}, - KindProcessor: {}, - KindExporter: {}, - KindExtension: {}, - } - for _, extension := range c.Service.Extensions { - toReturn[KindExtension][extension] = struct{}{} - } - - for _, pipeline := range c.Service.Pipelines { - if pipeline == nil { - continue - } - for _, componentId := range pipeline.Receivers { - toReturn[KindReceiver][componentId] = struct{}{} - } - for _, componentId := range pipeline.Exporters { - toReturn[KindExporter][componentId] = struct{}{} - } - for _, componentId := range pipeline.Processors { - toReturn[KindProcessor][componentId] = struct{}{} - } - } - for _, componentId := range c.Service.Extensions { - toReturn[KindExtension][componentId] = struct{}{} - } - return toReturn -} - -// getRbacRulesForComponentKinds gets the RBAC Rules for the given ComponentKind(s). -func (c *Config) getRbacRulesForComponentKinds(logger logr.Logger, componentKinds ...ComponentKind) ([]rbacv1.PolicyRule, error) { - var rules []rbacv1.PolicyRule - enabledComponents := c.GetEnabledComponents() - for _, componentKind := range componentKinds { - var retriever components.ParserRetriever - var cfg AnyConfig - switch componentKind { - case KindReceiver: - retriever = receivers.ReceiverFor - cfg = c.Receivers - case KindExporter: - retriever = exporters.ParserFor - cfg = c.Exporters - case KindProcessor: - retriever = processors.ProcessorFor - if c.Processors == nil { - cfg = AnyConfig{} - } else { - cfg = *c.Processors - } - case KindExtension: - retriever = extensions.ParserFor - if c.Extensions == nil { - cfg = AnyConfig{} - } else { - cfg = *c.Extensions - } - default: - logger.V(1).Info("unknown component kind", "kind", componentKind) - continue - } - for componentName := range enabledComponents[componentKind] { - // TODO: Clean up the naming here and make it simpler to use a retriever. - parser := retriever(componentName) - parsedRules, err := parser.GetRBACRules(logger, cfg.Object[componentName]) - if err != nil { - return nil, err - } - rules = append(rules, parsedRules...) - } - } - return rules, nil -} - -// getPortsForComponentKinds gets the ports for the given ComponentKind(s). -func (c *Config) getPortsForComponentKinds(logger logr.Logger, componentKinds ...ComponentKind) ([]corev1.ServicePort, error) { - var ports []corev1.ServicePort - enabledComponents := c.GetEnabledComponents() - for _, componentKind := range componentKinds { - var retriever components.ParserRetriever - var cfg AnyConfig - switch componentKind { - case KindReceiver: - retriever = receivers.ReceiverFor - cfg = c.Receivers - case KindExporter: - retriever = exporters.ParserFor - cfg = c.Exporters - case KindProcessor: - continue - case KindExtension: - retriever = extensions.ParserFor - if c.Extensions == nil { - cfg = AnyConfig{} - } else { - cfg = *c.Extensions - } - } - for componentName := range enabledComponents[componentKind] { - // TODO: Clean up the naming here and make it simpler to use a retriever. - parser := retriever(componentName) - parsedPorts, err := parser.Ports(logger, componentName, cfg.Object[componentName]) - if err != nil { - return nil, err - } - ports = append(ports, parsedPorts...) - } - } - - slices.SortFunc(ports, func(i, j corev1.ServicePort) int { - return strings.Compare(i.Name, j.Name) - }) - - return ports, nil -} - -// getEnvironmentVariablesForComponentKinds gets the environment variables for the given ComponentKind(s). -func (c *Config) getEnvironmentVariablesForComponentKinds(logger logr.Logger, componentKinds ...ComponentKind) ([]corev1.EnvVar, error) { - envVars := []corev1.EnvVar{} - enabledComponents := c.GetEnabledComponents() - for _, componentKind := range componentKinds { - var retriever components.ParserRetriever - var cfg AnyConfig - - switch componentKind { - case KindReceiver: - retriever = receivers.ReceiverFor - cfg = c.Receivers - case KindExporter, KindProcessor, KindExtension: - continue - } - for componentName := range enabledComponents[componentKind] { - parser := retriever(componentName) - parsedEnvVars, err := parser.GetEnvironmentVariables(logger, cfg.Object[componentName]) - if err != nil { - return nil, err - } - envVars = append(envVars, parsedEnvVars...) - } - } - - slices.SortFunc(envVars, func(i, j corev1.EnvVar) int { - return strings.Compare(i.Name, j.Name) - }) - - return envVars, nil -} - -// applyDefaultForComponentKinds applies defaults to the endpoints for the given ComponentKind(s). -// If defaultsCfg.TLSProfile is set, TLS defaults are also applied via the Parser.GetDefaultConfig method. -// Returns a list of events that should be recorded by the caller. -func (c *Config) applyDefaultForComponentKinds(logger logr.Logger, parserOpts []components.DefaultOption, componentKinds ...ComponentKind) ([]EventInfo, error) { - events, err := c.Service.ApplyDefaults(logger) - if err != nil { - return events, err - } - enabledComponents := c.GetEnabledComponents() - for _, componentKind := range componentKinds { - var retriever components.ParserRetriever - var cfg AnyConfig - switch componentKind { - case KindReceiver: - retriever = receivers.ReceiverFor - cfg = c.Receivers - case KindExporter, KindProcessor: - retriever = exporters.ParserFor - cfg = c.Exporters - case KindExtension: - if c.Extensions == nil { - continue - } - retriever = extensions.ParserFor - cfg = *c.Extensions - } - for componentName := range enabledComponents[componentKind] { - parser := retriever(componentName) - componentConf := cfg.Object[componentName] - newCfg, err := parser.GetDefaultConfig(logger, componentConf, parserOpts...) - if err != nil { - return events, err - } - - // We need to ensure we don't remove any fields in defaulting. - mappedCfg, ok := newCfg.(map[string]any) - if !ok || mappedCfg == nil { - logger.V(1).Info("returned default configuration invalid", - "warn", "could not apply component defaults", - "component", componentName, - ) - continue - } - - if componentConf == nil { - componentConf = map[string]any{} - } - if err := mergo.Merge(&mappedCfg, componentConf); err != nil { - return events, err - } - cfg.Object[componentName] = mappedCfg - } - } - - return events, nil -} - -func (c *Config) GetReceiverPorts(logger logr.Logger) ([]corev1.ServicePort, error) { - return c.getPortsForComponentKinds(logger, KindReceiver) -} - -func (c *Config) GetExporterPorts(logger logr.Logger) ([]corev1.ServicePort, error) { - return c.getPortsForComponentKinds(logger, KindExporter) -} - -func (c *Config) GetExtensionPorts(logger logr.Logger) ([]corev1.ServicePort, error) { - return c.getPortsForComponentKinds(logger, KindExtension) -} - -func (c *Config) GetReceiverAndExporterPorts(logger logr.Logger) ([]corev1.ServicePort, error) { - return c.getPortsForComponentKinds(logger, KindReceiver, KindExporter) -} - -func (c *Config) GetAllPorts(logger logr.Logger) ([]corev1.ServicePort, error) { - return c.getPortsForComponentKinds(logger, KindReceiver, KindExporter, KindExtension) -} - -func (c *Config) GetEnvironmentVariables(logger logr.Logger) ([]corev1.EnvVar, error) { - return c.getEnvironmentVariablesForComponentKinds(logger, KindReceiver) -} - -func (c *Config) GetAllRbacRules(logger logr.Logger) ([]rbacv1.PolicyRule, error) { - return c.getRbacRulesForComponentKinds(logger, KindReceiver, KindExporter, KindProcessor, KindExtension) -} - -// ApplyDefaults applies default configuration values to the collector config. -// Optional DefaultsOption arguments can be provided to customize behavior. -func (c *Config) ApplyDefaults(logger logr.Logger, opts ...components.DefaultOption) ([]EventInfo, error) { - return c.applyDefaultForComponentKinds(logger, opts, KindReceiver, KindExporter, KindExtension) -} - -// GetLivenessProbe gets the first enabled liveness probe. There should only ever be one extension enabled -// that provides the hinting for the liveness probe. -func (c *Config) GetLivenessProbe(logger logr.Logger) (*corev1.Probe, error) { - if c.Extensions == nil { - return nil, nil - } - - enabledComponents := c.GetEnabledComponents() - for componentName := range enabledComponents[KindExtension] { - // TODO: Clean up the naming here and make it simpler to use a retriever. - parser := extensions.ParserFor(componentName) - if probe, err := parser.GetLivenessProbe(logger, c.Extensions.Object[componentName]); err != nil { - return nil, err - } else if probe != nil { - return probe, nil - } - } - return nil, nil -} - -// GetReadinessProbe gets the first enabled readiness probe. There should only ever be one extension enabled -// that provides the hinting for the readiness probe. -func (c *Config) GetReadinessProbe(logger logr.Logger) (*corev1.Probe, error) { - if c.Extensions == nil { - return nil, nil - } - - enabledComponents := c.GetEnabledComponents() - for componentName := range enabledComponents[KindExtension] { - // TODO: Clean up the naming here and make it simpler to use a retriever. - parser := extensions.ParserFor(componentName) - if probe, err := parser.GetReadinessProbe(logger, c.Extensions.Object[componentName]); err != nil { - return nil, err - } else if probe != nil { - return probe, nil - } - } - return nil, nil -} - -// GetStartupProbe gets the first enabled startup probe. There should only ever be one extension enabled -// that provides the hinting for the startup probe. -func (c *Config) GetStartupProbe(logger logr.Logger) (*corev1.Probe, error) { - if c.Extensions == nil { - return nil, nil - } - - enabledComponents := c.GetEnabledComponents() - for componentName := range enabledComponents[KindExtension] { - // TODO: Clean up the naming here and make it simpler to use a retriever. - parser := extensions.ParserFor(componentName) - if probe, err := parser.GetStartupProbe(logger, c.Extensions.Object[componentName]); err != nil { - return nil, err - } else if probe != nil { - return probe, nil - } - } - return nil, nil -} - -// Yaml encodes the current object and returns it as a string. -func (c *Config) Yaml() (string, error) { - var buf bytes.Buffer - yamlEncoder := go_yaml.NewEncoder(&buf, go_yaml.IndentSequence(true), go_yaml.AutoInt()) - if err := yamlEncoder.Encode(&c); err != nil { - return "", err - } - return buf.String(), nil -} - -// NullObjects returns null objects in the config. -func (c *Config) NullObjects() []string { - var nullKeys []string - if nulls := getNullValuedKeys(c.Receivers.Object); len(nulls) > 0 { - nullKeys = append(nullKeys, addPrefix("receivers.", nulls)...) - } - if nulls := getNullValuedKeys(c.Exporters.Object); len(nulls) > 0 { - nullKeys = append(nullKeys, addPrefix("exporters.", nulls)...) - } - if c.Processors != nil { - if nulls := getNullValuedKeys(c.Processors.Object); len(nulls) > 0 { - nullKeys = append(nullKeys, addPrefix("processors.", nulls)...) - } - } - if c.Extensions != nil { - if nulls := getNullValuedKeys(c.Extensions.Object); len(nulls) > 0 { - nullKeys = append(nullKeys, addPrefix("extensions.", nulls)...) - } - } - if c.Connectors != nil { - if nulls := getNullValuedKeys(c.Connectors.Object); len(nulls) > 0 { - nullKeys = append(nullKeys, addPrefix("connectors.", nulls)...) - } - } - // Make the return deterministic. The config uses maps therefore processing order is non-deterministic. - slices.Sort(nullKeys) - return nullKeys -} - +// Service is the service section of the collector config. type Service struct { Extensions []string `json:"extensions,omitempty" yaml:"extensions,omitempty"` // +kubebuilder:pruning:PreserveUnknownFields @@ -479,107 +103,6 @@ type Service struct { Pipelines map[string]*Pipeline `json:"pipelines" yaml:"pipelines"` } -const ( - defaultServicePort int32 = 8888 - defaultServiceHost = "0.0.0.0" -) - -// MetricsEndpoint attempts gets the host and port number from the host address without doing any validation regarding the -// address itself. -// It works even before env var expansion happens, when a simple `net.SplitHostPort` would fail because of the extra colon -// from the env var, i.e. the address looks like "${env:POD_IP}:4317", "${env:POD_IP}", or "${POD_IP}". -// In cases which the port itself is a variable, i.e. "${env:POD_IP}:${env:PORT}", this returns an error. This happens -// because the port is used to generate Service objects and mappings. -func (s *Service) MetricsEndpoint(logger logr.Logger) (host string, port int32, err error) { - telemetry := s.GetTelemetry(logger) - if telemetry == nil { - return defaultServiceHost, defaultServicePort, nil - } - - if telemetry.Metrics.Address != "" && len(telemetry.Metrics.Readers) == 0 { - host, port, err := parseAddressEndpoint(telemetry.Metrics.Address) - if err != nil { - return "", 0, err - } - - return host, port, nil - } - - for _, r := range telemetry.Metrics.Readers { - if r.Pull == nil { - continue - } - prom := r.Pull.Exporter.Prometheus - if prom == nil { - continue - } - host := defaultServiceHost - if prom.Host != nil && *prom.Host != "" { - host = *prom.Host - } - port := defaultServicePort - if prom.Port != nil && *prom.Port != 0 { - if *prom.Port < 0 || *prom.Port > math.MaxUint16 { - return "", 0, fmt.Errorf("invalid prometheus metrics port: %d", *prom.Port) - } - port = int32(*prom.Port) - } - return host, port, nil - } - - return defaultServiceHost, defaultServicePort, nil -} - -// ApplyDefaults inserts configuration defaults if it has not been set. -// Returns a list of events that should be recorded by the caller. -func (s *Service) ApplyDefaults(logger logr.Logger) ([]EventInfo, error) { - var events []EventInfo - tel := s.GetTelemetry(logger) - - if tel == nil { - logger.V(2).Info("no telemetry configuration parsed, creating default") - tel = &Telemetry{} - s.Telemetry = &AnyConfig{ - Object: map[string]any{}, - } - } - - if tel.Metrics.Address != "" || len(tel.Metrics.Readers) != 0 { - // The user already set the address or the readers, so we don't need to do anything - logger.V(1).Info("telemetry configuration already provided by user, skipping defaults", - "metricsAddress", tel.Metrics.Address, - "readersCount", len(tel.Metrics.Readers)) - return events, nil - } - - logger.V(2).Info("no telemetry readers configuration found, applying default Prometheus endpoint") - - host, port, err := s.MetricsEndpoint(logger) - if err != nil { - logger.Error(err, "failed to determine metrics endpoint for default configuration") - return events, err - } - - reader := AddPrometheusMetricsEndpoint(host, port) - tel.Metrics.Readers = append(tel.Metrics.Readers, reader) - - events = append(events, EventInfo{ - Type: corev1.EventTypeNormal, - Reason: "Spec.Service.Telemetry.DefaultsApplied", - Message: fmt.Sprintf("Applied default Prometheus telemetry configuration (host: %s, port: %d)", host, port), - }) - - telConfig, err := tel.ToAnyConfig() - if err != nil { - return events, err - } - - if err := mergo.Merge(&s.Telemetry.Object, telConfig.Object); err != nil { - return events, err - } - return events, nil -} - // MetricsConfig comes from the collector. type MetricsConfig struct { // Level is the level of telemetry metrics, the possible values are: @@ -620,67 +143,3 @@ type Telemetry struct { // attribute must be specified in this map with null YAML value (nil string pointer). Resource map[string]*string `json:"resource,omitempty" yaml:"resource,omitempty"` } - -// ToAnyConfig converts the Telemetry struct to an AnyConfig struct. -func (t *Telemetry) ToAnyConfig() (*AnyConfig, error) { - data, err := json.Marshal(t) - if err != nil { - return nil, err - } - var result map[string]any - if err := json.Unmarshal(data, &result); err != nil { - return nil, err - } - - normalizeConfig(result) - - return &AnyConfig{ - Object: result, - }, nil -} - -func AddPrometheusMetricsEndpoint(host string, port int32) otelConfig.MetricReader { - portInt := int(port) - return otelConfig.MetricReader{ - Pull: &otelConfig.PullMetricReader{ - Exporter: otelConfig.PullMetricExporter{ - Prometheus: &otelConfig.Prometheus{ - Host: &host, - Port: &portInt, - }, - }, - }, - } -} - -// GetTelemetry serves as a helper function to access the fields we care about in the underlying telemetry struct. -// This exists to avoid needing to worry extra fields in the telemetry struct. -func (s *Service) GetTelemetry(logger logr.Logger) *Telemetry { - if s.Telemetry == nil { - logger.V(2).Info("no spec.service.telemetry configuration found") - return nil - } - - // Convert map to JSON bytes - jsonData, err := json.Marshal(s.Telemetry) - if err != nil { - logger.Error(err, "failed to marshal telemetry configuration to JSON", "telemetry", s.Telemetry.Object) - return nil - } - - logger.V(2).Info("marshaled telemetry configuration", "json", string(jsonData)) - - t := &Telemetry{} - // Unmarshal JSON into the provided struct - if err := json.Unmarshal(jsonData, t); err != nil { - logger.Error(err, "failed to unmarshal telemetry configuration, this may indicate invalid configuration", "json", string(jsonData), "originalConfig", s.Telemetry.Object) - return nil - } - - logger.V(2).Info("successfully parsed telemetry configuration", - "metricsLevel", t.Metrics.Level, - "metricsAddress", t.Metrics.Address, - "readersCount", len(t.Metrics.Readers)) - - return t -} diff --git a/apis/v1beta1/zz_generated.deepcopy.go b/apis/v1beta1/zz_generated.deepcopy.go index 06deb5de9c..645f024a9b 100644 --- a/apis/v1beta1/zz_generated.deepcopy.go +++ b/apis/v1beta1/zz_generated.deepcopy.go @@ -109,21 +109,6 @@ func (in *ConfigMapsSpec) DeepCopy() *ConfigMapsSpec { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *EventInfo) DeepCopyInto(out *EventInfo) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EventInfo. -func (in *EventInfo) DeepCopy() *EventInfo { - if in == nil { - return nil - } - out := new(EventInfo) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *HttpRouteConfig) DeepCopyInto(out *HttpRouteConfig) { *out = *in diff --git a/go.mod b/go.mod index 9c432ca4d1..35861284f9 100644 --- a/go.mod +++ b/go.mod @@ -41,7 +41,7 @@ require ( github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/featuregate v1.55.0 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.68.0 - go.opentelemetry.io/contrib/otelconf v0.23.0 // indirect + go.opentelemetry.io/contrib/otelconf v0.23.0 go.opentelemetry.io/otel v1.43.0 go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.43.0 go.opentelemetry.io/otel/exporters/prometheus v0.65.0 diff --git a/internal/apihelpers/v1beta1/config.go b/internal/apihelpers/v1beta1/config.go new file mode 100644 index 0000000000..d308c5e3d7 --- /dev/null +++ b/internal/apihelpers/v1beta1/config.go @@ -0,0 +1,542 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package apihelpers + +import ( + "bytes" + "encoding/json" + "fmt" + "slices" + "strings" + + "dario.cat/mergo" + "github.com/go-logr/logr" + go_yaml "github.com/goccy/go-yaml" + otelConfig "go.opentelemetry.io/contrib/otelconf/v0.3.0" + corev1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" + + "github.com/open-telemetry/opentelemetry-operator/apis/v1beta1" + "github.com/open-telemetry/opentelemetry-operator/internal/components" + "github.com/open-telemetry/opentelemetry-operator/internal/components/exporters" + "github.com/open-telemetry/opentelemetry-operator/internal/components/extensions" + "github.com/open-telemetry/opentelemetry-operator/internal/components/processors" + "github.com/open-telemetry/opentelemetry-operator/internal/components/receivers" +) + +// ComponentKind is the type of a component (receiver, exporter, processor, extension). +type ComponentKind int + +const ( + KindReceiver ComponentKind = iota + KindExporter + KindProcessor + KindExtension +) + +func (c ComponentKind) String() string { + return [...]string{"receiver", "exporter", "processor", "extension"}[c] +} + +// EventInfo represents an event to be recorded. +type EventInfo struct { + Type string + Reason string + Message string +} + +const ( + defaultServiceHost = "0.0.0.0" +) + +// GetEnabledComponents constructs a list of enabled components by component type. +func GetEnabledComponents(c *v1beta1.Config) map[ComponentKind]map[string]any { + toReturn := map[ComponentKind]map[string]any{ + KindReceiver: {}, + KindProcessor: {}, + KindExporter: {}, + KindExtension: {}, + } + for _, extension := range c.Service.Extensions { + toReturn[KindExtension][extension] = struct{}{} + } + + for _, pipeline := range c.Service.Pipelines { + if pipeline == nil { + continue + } + for _, componentId := range pipeline.Receivers { + toReturn[KindReceiver][componentId] = struct{}{} + } + for _, componentId := range pipeline.Exporters { + toReturn[KindExporter][componentId] = struct{}{} + } + for _, componentId := range pipeline.Processors { + toReturn[KindProcessor][componentId] = struct{}{} + } + } + for _, componentId := range c.Service.Extensions { + toReturn[KindExtension][componentId] = struct{}{} + } + return toReturn +} + +// getRbacRulesForComponentKinds gets the RBAC Rules for the given ComponentKind(s). +func getRbacRulesForComponentKinds(c *v1beta1.Config, logger logr.Logger, componentKinds ...ComponentKind) ([]rbacv1.PolicyRule, error) { + var rules []rbacv1.PolicyRule + enabledComponents := GetEnabledComponents(c) + for _, componentKind := range componentKinds { + var retriever components.ParserRetriever + var cfg v1beta1.AnyConfig + switch componentKind { + case KindReceiver: + retriever = receivers.ReceiverFor + cfg = c.Receivers + case KindExporter: + retriever = exporters.ParserFor + cfg = c.Exporters + case KindProcessor: + retriever = processors.ProcessorFor + if c.Processors == nil { + cfg = v1beta1.AnyConfig{} + } else { + cfg = *c.Processors + } + case KindExtension: + retriever = extensions.ParserFor + if c.Extensions == nil { + cfg = v1beta1.AnyConfig{} + } else { + cfg = *c.Extensions + } + default: + logger.V(1).Info("unknown component kind", "kind", componentKind) + continue + } + for componentName := range enabledComponents[componentKind] { + parser := retriever(componentName) + parsedRules, err := parser.GetRBACRules(logger, cfg.Object[componentName]) + if err != nil { + return nil, err + } + rules = append(rules, parsedRules...) + } + } + return rules, nil +} + +// getPortsForComponentKinds gets the ports for the given ComponentKind(s). +func getPortsForComponentKinds(c *v1beta1.Config, logger logr.Logger, componentKinds ...ComponentKind) ([]corev1.ServicePort, error) { + var ports []corev1.ServicePort + enabledComponents := GetEnabledComponents(c) + for _, componentKind := range componentKinds { + var retriever components.ParserRetriever + var cfg v1beta1.AnyConfig + switch componentKind { + case KindReceiver: + retriever = receivers.ReceiverFor + cfg = c.Receivers + case KindExporter: + retriever = exporters.ParserFor + cfg = c.Exporters + case KindProcessor: + continue + case KindExtension: + retriever = extensions.ParserFor + if c.Extensions == nil { + cfg = v1beta1.AnyConfig{} + } else { + cfg = *c.Extensions + } + } + for componentName := range enabledComponents[componentKind] { + parser := retriever(componentName) + parsedPorts, err := parser.Ports(logger, componentName, cfg.Object[componentName]) + if err != nil { + return nil, err + } + ports = append(ports, parsedPorts...) + } + } + + slices.SortFunc(ports, func(i, j corev1.ServicePort) int { + return strings.Compare(i.Name, j.Name) + }) + + return ports, nil +} + +// getEnvironmentVariablesForComponentKinds gets the environment variables for the given ComponentKind(s). +func getEnvironmentVariablesForComponentKinds(c *v1beta1.Config, logger logr.Logger, componentKinds ...ComponentKind) ([]corev1.EnvVar, error) { + envVars := []corev1.EnvVar{} + enabledComponents := GetEnabledComponents(c) + for _, componentKind := range componentKinds { + var retriever components.ParserRetriever + var cfg v1beta1.AnyConfig + + switch componentKind { + case KindReceiver: + retriever = receivers.ReceiverFor + cfg = c.Receivers + case KindExporter, KindProcessor, KindExtension: + continue + } + for componentName := range enabledComponents[componentKind] { + parser := retriever(componentName) + parsedEnvVars, err := parser.GetEnvironmentVariables(logger, cfg.Object[componentName]) + if err != nil { + return nil, err + } + envVars = append(envVars, parsedEnvVars...) + } + } + + slices.SortFunc(envVars, func(i, j corev1.EnvVar) int { + return strings.Compare(i.Name, j.Name) + }) + + return envVars, nil +} + +// applyDefaultForComponentKinds applies defaults to the endpoints for the given ComponentKind(s). +func applyDefaultForComponentKinds(c *v1beta1.Config, logger logr.Logger, parserOpts []components.DefaultOption, componentKinds ...ComponentKind) ([]EventInfo, error) { + events, err := ServiceApplyDefaults(&c.Service, logger) + if err != nil { + return events, err + } + enabledComponents := GetEnabledComponents(c) + for _, componentKind := range componentKinds { + var retriever components.ParserRetriever + var cfg v1beta1.AnyConfig + switch componentKind { + case KindReceiver: + retriever = receivers.ReceiverFor + cfg = c.Receivers + case KindExporter, KindProcessor: + retriever = exporters.ParserFor + cfg = c.Exporters + case KindExtension: + if c.Extensions == nil { + continue + } + retriever = extensions.ParserFor + cfg = *c.Extensions + } + for componentName := range enabledComponents[componentKind] { + parser := retriever(componentName) + componentConf := cfg.Object[componentName] + newCfg, err := parser.GetDefaultConfig(logger, componentConf, parserOpts...) + if err != nil { + return events, err + } + + // We need to ensure we don't remove any fields in defaulting. + mappedCfg, ok := newCfg.(map[string]any) + if !ok || mappedCfg == nil { + logger.V(1).Info("returned default configuration invalid", + "warn", "could not apply component defaults", + "component", componentName, + ) + continue + } + + if componentConf == nil { + componentConf = map[string]any{} + } + if err := mergo.Merge(&mappedCfg, componentConf); err != nil { + return events, err + } + cfg.Object[componentName] = mappedCfg + } + } + + return events, nil +} + +// GetReceiverPorts returns the ports for the receivers. +func GetReceiverPorts(c *v1beta1.Config, logger logr.Logger) ([]corev1.ServicePort, error) { + return getPortsForComponentKinds(c, logger, KindReceiver) +} + +// GetExporterPorts returns the ports for the exporters. +func GetExporterPorts(c *v1beta1.Config, logger logr.Logger) ([]corev1.ServicePort, error) { + return getPortsForComponentKinds(c, logger, KindExporter) +} + +// GetExtensionPorts returns the ports for the extensions. +func GetExtensionPorts(c *v1beta1.Config, logger logr.Logger) ([]corev1.ServicePort, error) { + return getPortsForComponentKinds(c, logger, KindExtension) +} + +// GetReceiverAndExporterPorts returns the ports for the receivers and exporters. +func GetReceiverAndExporterPorts(c *v1beta1.Config, logger logr.Logger) ([]corev1.ServicePort, error) { + return getPortsForComponentKinds(c, logger, KindReceiver, KindExporter) +} + +// GetAllPorts returns all ports for the receivers, exporters, and extensions. +func GetAllPorts(c *v1beta1.Config, logger logr.Logger) ([]corev1.ServicePort, error) { + return getPortsForComponentKinds(c, logger, KindReceiver, KindExporter, KindExtension) +} + +// GetEnvironmentVariables returns the environment variables for the receivers. +func GetEnvironmentVariables(c *v1beta1.Config, logger logr.Logger) ([]corev1.EnvVar, error) { + return getEnvironmentVariablesForComponentKinds(c, logger, KindReceiver) +} + +// GetAllRbacRules returns all RBAC rules. +func GetAllRbacRules(c *v1beta1.Config, logger logr.Logger) ([]rbacv1.PolicyRule, error) { + return getRbacRulesForComponentKinds(c, logger, KindReceiver, KindExporter, KindProcessor, KindExtension) +} + +// ApplyDefaults applies default configuration values to the collector config. +func ApplyDefaults(c *v1beta1.Config, logger logr.Logger, opts ...components.DefaultOption) ([]EventInfo, error) { + return applyDefaultForComponentKinds(c, logger, opts, KindReceiver, KindExporter, KindExtension) +} + +// GetLivenessProbe gets the first enabled liveness probe. +func GetLivenessProbe(c *v1beta1.Config, logger logr.Logger) (*corev1.Probe, error) { + if c.Extensions == nil { + return nil, nil + } + + enabledComponents := GetEnabledComponents(c) + for componentName := range enabledComponents[KindExtension] { + parser := extensions.ParserFor(componentName) + if probe, err := parser.GetLivenessProbe(logger, c.Extensions.Object[componentName]); err != nil { + return nil, err + } else if probe != nil { + return probe, nil + } + } + return nil, nil +} + +// GetReadinessProbe gets the first enabled readiness probe. +func GetReadinessProbe(c *v1beta1.Config, logger logr.Logger) (*corev1.Probe, error) { + if c.Extensions == nil { + return nil, nil + } + + enabledComponents := GetEnabledComponents(c) + for componentName := range enabledComponents[KindExtension] { + parser := extensions.ParserFor(componentName) + if probe, err := parser.GetReadinessProbe(logger, c.Extensions.Object[componentName]); err != nil { + return nil, err + } else if probe != nil { + return probe, nil + } + } + return nil, nil +} + +// GetStartupProbe gets the first enabled startup probe. +func GetStartupProbe(c *v1beta1.Config, logger logr.Logger) (*corev1.Probe, error) { + if c.Extensions == nil { + return nil, nil + } + + enabledComponents := GetEnabledComponents(c) + for componentName := range enabledComponents[KindExtension] { + parser := extensions.ParserFor(componentName) + if probe, err := parser.GetStartupProbe(logger, c.Extensions.Object[componentName]); err != nil { + return nil, err + } else if probe != nil { + return probe, nil + } + } + return nil, nil +} + +// Yaml encodes the config and returns it as a YAML string. +func Yaml(c *v1beta1.Config) (string, error) { + var buf bytes.Buffer + yamlEncoder := go_yaml.NewEncoder(&buf, go_yaml.IndentSequence(true), go_yaml.AutoInt()) + if err := yamlEncoder.Encode(c); err != nil { + return "", err + } + return buf.String(), nil +} + +// NullObjects returns null objects in the config. +func NullObjects(c *v1beta1.Config) []string { + var nullKeys []string + if nulls := getNullValuedKeys(c.Receivers.Object); len(nulls) > 0 { + nullKeys = append(nullKeys, addPrefix("receivers.", nulls)...) + } + if nulls := getNullValuedKeys(c.Exporters.Object); len(nulls) > 0 { + nullKeys = append(nullKeys, addPrefix("exporters.", nulls)...) + } + if c.Processors != nil { + if nulls := getNullValuedKeys(c.Processors.Object); len(nulls) > 0 { + nullKeys = append(nullKeys, addPrefix("processors.", nulls)...) + } + } + if c.Extensions != nil { + if nulls := getNullValuedKeys(c.Extensions.Object); len(nulls) > 0 { + nullKeys = append(nullKeys, addPrefix("extensions.", nulls)...) + } + } + if c.Connectors != nil { + if nulls := getNullValuedKeys(c.Connectors.Object); len(nulls) > 0 { + nullKeys = append(nullKeys, addPrefix("connectors.", nulls)...) + } + } + // Make the return deterministic. The config uses maps therefore processing order is non-deterministic. + slices.Sort(nullKeys) + return nullKeys +} + +// MetricsEndpoint attempts to get the host and port number from the service telemetry config. +func MetricsEndpoint(s *v1beta1.Service, logger logr.Logger) (host string, port int32, err error) { + telemetry := GetTelemetry(s, logger) + if telemetry == nil { + return defaultServiceHost, defaultServicePort, nil + } + + if telemetry.Metrics.Address != "" && len(telemetry.Metrics.Readers) == 0 { + host, port, err := parseAddressEndpoint(telemetry.Metrics.Address) + if err != nil { + return "", 0, err + } + + return host, port, nil + } + + for _, r := range telemetry.Metrics.Readers { + if r.Pull == nil { + continue + } + prom := r.Pull.Exporter.Prometheus + if prom == nil { + continue + } + host := defaultServiceHost + if prom.Host != nil && *prom.Host != "" { + host = *prom.Host + } + port := defaultServicePort + if prom.Port != nil && *prom.Port != 0 { + if *prom.Port < 0 || *prom.Port > 65535 { + return "", 0, fmt.Errorf("invalid prometheus metrics port: %d", *prom.Port) + } + port = int32(*prom.Port) + } + return host, port, nil + } + + return defaultServiceHost, defaultServicePort, nil +} + +// ServiceApplyDefaults inserts configuration defaults if not set. +func ServiceApplyDefaults(s *v1beta1.Service, logger logr.Logger) ([]EventInfo, error) { + var events []EventInfo + tel := GetTelemetry(s, logger) + + if tel == nil { + logger.V(2).Info("no telemetry configuration parsed, creating default") + tel = &v1beta1.Telemetry{} + s.Telemetry = &v1beta1.AnyConfig{ + Object: map[string]any{}, + } + } + + if tel.Metrics.Address != "" || len(tel.Metrics.Readers) != 0 { + logger.V(1).Info("telemetry configuration already provided by user, skipping defaults", + "metricsAddress", tel.Metrics.Address, + "readersCount", len(tel.Metrics.Readers)) + return events, nil + } + + logger.V(2).Info("no telemetry readers configuration found, applying default Prometheus endpoint") + + host, port, err := MetricsEndpoint(s, logger) + if err != nil { + logger.Error(err, "failed to determine metrics endpoint for default configuration") + return events, err + } + + reader := AddPrometheusMetricsEndpoint(host, port) + tel.Metrics.Readers = append(tel.Metrics.Readers, reader) + + events = append(events, EventInfo{ + Type: corev1.EventTypeNormal, + Reason: "Spec.Service.Telemetry.DefaultsApplied", + Message: fmt.Sprintf("Applied default Prometheus telemetry configuration (host: %s, port: %d)", host, port), + }) + + telConfig, err := ToAnyConfig(tel) + if err != nil { + return events, err + } + + if err := mergo.Merge(&s.Telemetry.Object, telConfig.Object); err != nil { + return events, err + } + return events, nil +} + +// GetTelemetry extracts the telemetry settings from the service config. +func GetTelemetry(s *v1beta1.Service, logger logr.Logger) *v1beta1.Telemetry { + if s.Telemetry == nil { + logger.V(2).Info("no spec.service.telemetry configuration found") + return nil + } + + // Convert map to JSON bytes + jsonData, err := json.Marshal(s.Telemetry) + if err != nil { + logger.Error(err, "failed to marshal telemetry configuration to JSON", "telemetry", s.Telemetry.Object) + return nil + } + + logger.V(2).Info("marshaled telemetry configuration", "json", string(jsonData)) + + t := &v1beta1.Telemetry{} + // Unmarshal JSON into the provided struct + if err := json.Unmarshal(jsonData, t); err != nil { + logger.Error(err, "failed to unmarshal telemetry configuration, this may indicate invalid configuration", "json", string(jsonData), "originalConfig", s.Telemetry.Object) + return nil + } + + logger.V(2).Info("successfully parsed telemetry configuration", + "metricsLevel", t.Metrics.Level, + "metricsAddress", t.Metrics.Address, + "readersCount", len(t.Metrics.Readers)) + + return t +} + +// ToAnyConfig converts the Telemetry struct to an AnyConfig struct. +func ToAnyConfig(t *v1beta1.Telemetry) (*v1beta1.AnyConfig, error) { + data, err := json.Marshal(t) + if err != nil { + return nil, err + } + var result map[string]any + if err := json.Unmarshal(data, &result); err != nil { + return nil, err + } + + normalizeConfig(result) + + return &v1beta1.AnyConfig{ + Object: result, + }, nil +} + +// AddPrometheusMetricsEndpoint creates a MetricReader for a Prometheus pull endpoint. +func AddPrometheusMetricsEndpoint(host string, port int32) otelConfig.MetricReader { + portInt := int(port) + return otelConfig.MetricReader{ + Pull: &otelConfig.PullMetricReader{ + Exporter: otelConfig.PullMetricExporter{ + Prometheus: &otelConfig.Prometheus{ + Host: &host, + Port: &portInt, + }, + }, + }, + } +} + diff --git a/apis/v1beta1/config_test.go b/internal/apihelpers/v1beta1/config_test.go similarity index 76% rename from apis/v1beta1/config_test.go rename to internal/apihelpers/v1beta1/config_test.go index 3a45d24262..3c92c84d07 100644 --- a/apis/v1beta1/config_test.go +++ b/internal/apihelpers/v1beta1/config_test.go @@ -1,7 +1,7 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -package v1beta1 +package apihelpers import ( "encoding/json" @@ -18,10 +18,15 @@ import ( v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/utils/ptr" + + "github.com/open-telemetry/opentelemetry-operator/apis/v1beta1" ) +// testdataPath returns the path to the testdata directory, which is shared from apis/v1beta1. +const testdataPath = "../../../apis/v1beta1/testdata" + func TestConfigFiles(t *testing.T) { - files, err := os.ReadDir("./testdata") + files, err := os.ReadDir(testdataPath) require.NoError(t, err) for _, file := range files { @@ -29,7 +34,7 @@ func TestConfigFiles(t *testing.T) { continue } - testFile := path.Join("./testdata", file.Name()) + testFile := path.Join(testdataPath, file.Name()) t.Run(testFile, func(t *testing.T) { collectorYaml, err := os.ReadFile(testFile) require.NoError(t, err) @@ -37,7 +42,7 @@ func TestConfigFiles(t *testing.T) { collectorJson, err := go_yaml.YAMLToJSON(collectorYaml) require.NoError(t, err) - cfg := &Config{} + cfg := &v1beta1.Config{} err = json.Unmarshal(collectorJson, cfg) require.NoError(t, err) jsonCfg, err := json.Marshal(cfg) @@ -52,38 +57,38 @@ func TestConfigFiles(t *testing.T) { } func TestNullObjects(t *testing.T) { - collectorYaml, err := os.ReadFile("./testdata/otelcol-null-values.yaml") + collectorYaml, err := os.ReadFile(path.Join(testdataPath, "otelcol-null-values.yaml")) require.NoError(t, err) collectorJson, err := go_yaml.YAMLToJSON(collectorYaml) require.NoError(t, err) - cfg := &Config{} + cfg := &v1beta1.Config{} err = json.Unmarshal(collectorJson, cfg) require.NoError(t, err) - nullObjects := cfg.NullObjects() + nullObjects := NullObjects(cfg) assert.Equal(t, []string{"connectors.spanmetrics:", "exporters.otlp.endpoint:", "extensions.health_check:", "processors.batch:", "receivers.otlp.protocols.grpc:", "receivers.otlp.protocols.http:"}, nullObjects) } func TestNullObjects_issue_3445(t *testing.T) { - collectorYaml, err := os.ReadFile("./testdata/issue-3452.yaml") + collectorYaml, err := os.ReadFile(path.Join(testdataPath, "issue-3452.yaml")) require.NoError(t, err) collectorJson, err := go_yaml.YAMLToJSON(collectorYaml) require.NoError(t, err) - cfg := &Config{} + cfg := &v1beta1.Config{} err = json.Unmarshal(collectorJson, cfg) require.NoError(t, err) - _, err = cfg.ApplyDefaults(logr.Discard()) + _, err = ApplyDefaults(cfg, logr.Discard()) require.NoError(t, err) - assert.Empty(t, cfg.NullObjects()) + assert.Empty(t, NullObjects(cfg)) } func TestConfigFiles_go_yaml(t *testing.T) { - files, err := os.ReadDir("./testdata") + files, err := os.ReadDir(testdataPath) require.NoError(t, err) for _, file := range files { @@ -91,12 +96,12 @@ func TestConfigFiles_go_yaml(t *testing.T) { continue } - testFile := path.Join("./testdata", file.Name()) + testFile := path.Join(testdataPath, file.Name()) t.Run(testFile, func(t *testing.T) { collectorYaml, err := os.ReadFile(testFile) require.NoError(t, err) - cfg := &Config{} + cfg := &v1beta1.Config{} err = go_yaml.Unmarshal(collectorYaml, cfg) require.NoError(t, err) yamlCfg, err := go_yaml.Marshal(cfg) @@ -109,52 +114,52 @@ func TestConfigFiles_go_yaml(t *testing.T) { } func TestNullObjects_go_yaml(t *testing.T) { - collectorYaml, err := os.ReadFile("./testdata/otelcol-null-values.yaml") + collectorYaml, err := os.ReadFile(path.Join(testdataPath, "otelcol-null-values.yaml")) require.NoError(t, err) - cfg := &Config{} + cfg := &v1beta1.Config{} err = go_yaml.Unmarshal(collectorYaml, cfg) require.NoError(t, err) - nullObjects := cfg.NullObjects() + nullObjects := NullObjects(cfg) assert.Equal(t, []string{"connectors.spanmetrics:", "exporters.otlp.endpoint:", "extensions.health_check:", "processors.batch:", "receivers.otlp.protocols.grpc:", "receivers.otlp.protocols.http:"}, nullObjects) } func TestConfigYaml(t *testing.T) { - cfg := &Config{ - Receivers: AnyConfig{ + cfg := &v1beta1.Config{ + Receivers: v1beta1.AnyConfig{ Object: map[string]any{ "otlp": nil, }, }, - Processors: &AnyConfig{ + Processors: &v1beta1.AnyConfig{ Object: map[string]any{ "modify_2000": "enabled", }, }, - Exporters: AnyConfig{ + Exporters: v1beta1.AnyConfig{ Object: map[string]any{ "otlp/exporter": nil, }, }, - Connectors: &AnyConfig{ + Connectors: &v1beta1.AnyConfig{ Object: map[string]any{ "con": "magic", }, }, - Extensions: &AnyConfig{ + Extensions: &v1beta1.AnyConfig{ Object: map[string]any{ "addon": "option1", }, }, - Service: Service{ + Service: v1beta1.Service{ Extensions: []string{"addon"}, - Telemetry: &AnyConfig{ + Telemetry: &v1beta1.AnyConfig{ Object: map[string]any{ "insights": "yeah!", }, }, - Pipelines: map[string]*Pipeline{ + Pipelines: map[string]*v1beta1.Pipeline{ "traces": { Receivers: []string{"otlp"}, Processors: []string{"modify_2000"}, @@ -163,7 +168,7 @@ func TestConfigYaml(t *testing.T) { }, }, } - yamlCollector, err := cfg.Yaml() + yamlCollector, err := Yaml(cfg) require.NoError(t, err) const expected = `receivers: @@ -196,31 +201,31 @@ service: } func TestGetTelemetryFromYAML(t *testing.T) { - collectorYaml, err := os.ReadFile("./testdata/otelcol-demo.yaml") + collectorYaml, err := os.ReadFile(path.Join(testdataPath, "otelcol-demo.yaml")) require.NoError(t, err) - cfg := &Config{} + cfg := &v1beta1.Config{} err = go_yaml.Unmarshal(collectorYaml, cfg) require.NoError(t, err) - telemetry := &Telemetry{ - Metrics: MetricsConfig{ + telemetry := &v1beta1.Telemetry{ + Metrics: v1beta1.MetricsConfig{ Level: "detailed", Address: "0.0.0.0:8888", }, } logger := logr.Discard() - assert.Equal(t, telemetry, cfg.Service.GetTelemetry(logger)) + assert.Equal(t, telemetry, GetTelemetry(&cfg.Service, logger)) } func TestGetTelemetryFromYAMLIsNil(t *testing.T) { - collectorYaml, err := os.ReadFile("./testdata/otelcol-couchbase.yaml") + collectorYaml, err := os.ReadFile(path.Join(testdataPath, "otelcol-couchbase.yaml")) require.NoError(t, err) - cfg := &Config{} + cfg := &v1beta1.Config{} err = go_yaml.Unmarshal(collectorYaml, cfg) require.NoError(t, err) logger := logr.Discard() - assert.Nil(t, cfg.Service.GetTelemetry(logger)) + assert.Nil(t, GetTelemetry(&cfg.Service, logger)) } func TestConfigMetricsEndpoint(t *testing.T) { @@ -229,14 +234,14 @@ func TestConfigMetricsEndpoint(t *testing.T) { expectedAddr string expectedPort int32 expectedErr bool - config Service + config v1beta1.Service }{ { desc: "custom port", expectedAddr: "localhost", expectedPort: 9090, - config: Service{ - Telemetry: &AnyConfig{ + config: v1beta1.Service{ + Telemetry: &v1beta1.AnyConfig{ Object: map[string]any{ "metrics": map[string]any{ "address": "localhost:9090", @@ -249,8 +254,8 @@ func TestConfigMetricsEndpoint(t *testing.T) { desc: "custom port ipv6", expectedAddr: "[::]", expectedPort: 9090, - config: Service{ - Telemetry: &AnyConfig{ + config: v1beta1.Service{ + Telemetry: &v1beta1.AnyConfig{ Object: map[string]any{ "metrics": map[string]any{ "address": "[::]:9090", @@ -263,8 +268,8 @@ func TestConfigMetricsEndpoint(t *testing.T) { desc: "missing port", expectedAddr: "localhost", expectedPort: 8888, - config: Service{ - Telemetry: &AnyConfig{ + config: v1beta1.Service{ + Telemetry: &v1beta1.AnyConfig{ Object: map[string]any{ "metrics": map[string]any{ "address": "localhost", @@ -277,8 +282,8 @@ func TestConfigMetricsEndpoint(t *testing.T) { desc: "missing port ipv6", expectedAddr: "[::]", expectedPort: 8888, - config: Service{ - Telemetry: &AnyConfig{ + config: v1beta1.Service{ + Telemetry: &v1beta1.AnyConfig{ Object: map[string]any{ "metrics": map[string]any{ "address": "[::]", @@ -291,8 +296,8 @@ func TestConfigMetricsEndpoint(t *testing.T) { desc: "env var and missing port", expectedAddr: "${env:POD_IP}", expectedPort: 8888, - config: Service{ - Telemetry: &AnyConfig{ + config: v1beta1.Service{ + Telemetry: &v1beta1.AnyConfig{ Object: map[string]any{ "metrics": map[string]any{ "address": "${env:POD_IP}", @@ -305,8 +310,8 @@ func TestConfigMetricsEndpoint(t *testing.T) { desc: "env var and missing port ipv6", expectedAddr: "[${env:POD_IP}]", expectedPort: 8888, - config: Service{ - Telemetry: &AnyConfig{ + config: v1beta1.Service{ + Telemetry: &v1beta1.AnyConfig{ Object: map[string]any{ "metrics": map[string]any{ "address": "[${env:POD_IP}]", @@ -319,8 +324,8 @@ func TestConfigMetricsEndpoint(t *testing.T) { desc: "env var and with port", expectedAddr: "${POD_IP}", expectedPort: 1234, - config: Service{ - Telemetry: &AnyConfig{ + config: v1beta1.Service{ + Telemetry: &v1beta1.AnyConfig{ Object: map[string]any{ "metrics": map[string]any{ "address": "${POD_IP}:1234", @@ -333,8 +338,8 @@ func TestConfigMetricsEndpoint(t *testing.T) { desc: "env var and with port ipv6", expectedAddr: "[${POD_IP}]", expectedPort: 1234, - config: Service{ - Telemetry: &AnyConfig{ + config: v1beta1.Service{ + Telemetry: &v1beta1.AnyConfig{ Object: map[string]any{ "metrics": map[string]any{ "address": "[${POD_IP}]:1234", @@ -346,8 +351,8 @@ func TestConfigMetricsEndpoint(t *testing.T) { { desc: "port is env var", expectedErr: true, - config: Service{ - Telemetry: &AnyConfig{ + config: v1beta1.Service{ + Telemetry: &v1beta1.AnyConfig{ Object: map[string]any{ "metrics": map[string]any{ "address": "localhost:${env:POD_PORT}", @@ -359,8 +364,8 @@ func TestConfigMetricsEndpoint(t *testing.T) { { desc: "port is env var ipv6", expectedErr: true, - config: Service{ - Telemetry: &AnyConfig{ + config: v1beta1.Service{ + Telemetry: &v1beta1.AnyConfig{ Object: map[string]any{ "metrics": map[string]any{ "address": "[::]:${env:POD_PORT}", @@ -373,8 +378,8 @@ func TestConfigMetricsEndpoint(t *testing.T) { desc: "missing address", expectedAddr: "0.0.0.0", expectedPort: 8888, - config: Service{ - Telemetry: &AnyConfig{ + config: v1beta1.Service{ + Telemetry: &v1beta1.AnyConfig{ Object: map[string]any{ "metrics": map[string]any{ "level": "detailed", @@ -387,8 +392,8 @@ func TestConfigMetricsEndpoint(t *testing.T) { desc: "missing metrics", expectedAddr: "0.0.0.0", expectedPort: 8888, - config: Service{ - Telemetry: &AnyConfig{}, + config: v1beta1.Service{ + Telemetry: &v1beta1.AnyConfig{}, }, }, { @@ -400,8 +405,8 @@ func TestConfigMetricsEndpoint(t *testing.T) { desc: "configured telemetry", expectedAddr: "1.2.3.4", expectedPort: 4567, - config: Service{ - Telemetry: &AnyConfig{ + config: v1beta1.Service{ + Telemetry: &v1beta1.AnyConfig{ Object: map[string]any{ "metrics": map[string]any{ "address": "1.2.3.4:4567", @@ -414,8 +419,8 @@ func TestConfigMetricsEndpoint(t *testing.T) { desc: "derive from readers prometheus host+port", expectedAddr: "0.0.0.0", expectedPort: 8889, - config: Service{ - Telemetry: &AnyConfig{ + config: v1beta1.Service{ + Telemetry: &v1beta1.AnyConfig{ Object: map[string]any{ "metrics": map[string]any{ "level": "detailed", @@ -440,8 +445,8 @@ func TestConfigMetricsEndpoint(t *testing.T) { desc: "derive from readers prometheus port only (default host)", expectedAddr: "0.0.0.0", expectedPort: 8899, - config: Service{ - Telemetry: &AnyConfig{ + config: v1beta1.Service{ + Telemetry: &v1beta1.AnyConfig{ Object: map[string]any{ "metrics": map[string]any{ "readers": []any{ @@ -464,8 +469,8 @@ func TestConfigMetricsEndpoint(t *testing.T) { desc: "derive from readers prometheus host only (default port)", expectedAddr: "127.0.0.1", expectedPort: 8888, - config: Service{ - Telemetry: &AnyConfig{ + config: v1beta1.Service{ + Telemetry: &v1beta1.AnyConfig{ Object: map[string]any{ "metrics": map[string]any{ "readers": []any{ @@ -488,8 +493,8 @@ func TestConfigMetricsEndpoint(t *testing.T) { desc: "readers takes precedence over address", expectedAddr: "0.0.0.0", expectedPort: 8889, - config: Service{ - Telemetry: &AnyConfig{ + config: v1beta1.Service{ + Telemetry: &v1beta1.AnyConfig{ Object: map[string]any{ "metrics": map[string]any{ "address": "1.2.3.4:4567", @@ -514,8 +519,8 @@ func TestConfigMetricsEndpoint(t *testing.T) { desc: "readers present but no prometheus -> defaults", expectedAddr: "0.0.0.0", expectedPort: 8888, - config: Service{ - Telemetry: &AnyConfig{ + config: v1beta1.Service{ + Telemetry: &v1beta1.AnyConfig{ Object: map[string]any{ "metrics": map[string]any{ "readers": []any{ @@ -540,8 +545,7 @@ func TestConfigMetricsEndpoint(t *testing.T) { }, } { t.Run(tt.desc, func(t *testing.T) { - // these are acceptable failures, we return to the collector's default metric port - addr, port, err := tt.config.MetricsEndpoint(logr.Discard()) + addr, port, err := MetricsEndpoint(&tt.config, logr.Discard()) if tt.expectedErr { assert.Error(t, err) } else { @@ -561,7 +565,7 @@ func TestConfig_GetEnabledComponents(t *testing.T) { }{ { name: "connectors", - file: "testdata/otelcol-connectors.yaml", + file: path.Join(testdataPath, "otelcol-connectors.yaml"), want: map[ComponentKind]map[string]any{ KindReceiver: { "foo": struct{}{}, @@ -577,7 +581,7 @@ func TestConfig_GetEnabledComponents(t *testing.T) { }, { name: "couchbase", - file: "testdata/otelcol-couchbase.yaml", + file: path.Join(testdataPath, "otelcol-couchbase.yaml"), want: map[ComponentKind]map[string]any{ KindReceiver: { "prometheus/couchbase": struct{}{}, @@ -595,7 +599,7 @@ func TestConfig_GetEnabledComponents(t *testing.T) { }, { name: "demo", - file: "testdata/otelcol-demo.yaml", + file: path.Join(testdataPath, "otelcol-demo.yaml"), want: map[ComponentKind]map[string]any{ KindReceiver: { "otlp": struct{}{}, @@ -618,7 +622,7 @@ func TestConfig_GetEnabledComponents(t *testing.T) { }, { name: "extensions", - file: "testdata/otelcol-extensions.yaml", + file: path.Join(testdataPath, "otelcol-extensions.yaml"), want: map[ComponentKind]map[string]any{ KindReceiver: { "otlp": struct{}{}, @@ -634,7 +638,7 @@ func TestConfig_GetEnabledComponents(t *testing.T) { }, { name: "filelog", - file: "testdata/otelcol-filelog.yaml", + file: path.Join(testdataPath, "otelcol-filelog.yaml"), want: map[ComponentKind]map[string]any{ KindReceiver: { "filelog": struct{}{}, @@ -648,7 +652,7 @@ func TestConfig_GetEnabledComponents(t *testing.T) { }, { name: "null", - file: "testdata/otelcol-null-values.yaml", + file: path.Join(testdataPath, "otelcol-null-values.yaml"), want: map[ComponentKind]map[string]any{ KindReceiver: {}, KindProcessor: {}, @@ -662,10 +666,10 @@ func TestConfig_GetEnabledComponents(t *testing.T) { collectorYaml, err := os.ReadFile(tt.file) require.NoError(t, err) - c := &Config{} + c := &v1beta1.Config{} err = go_yaml.Unmarshal(collectorYaml, c) require.NoError(t, err) - assert.Equalf(t, tt.want, c.GetEnabledComponents(), "GetEnabledComponents()") + assert.Equalf(t, tt.want, GetEnabledComponents(c), "GetEnabledComponents()") }) } } @@ -673,22 +677,22 @@ func TestConfig_GetEnabledComponents(t *testing.T) { func TestConfig_getEnvironmentVariablesForComponentKinds(t *testing.T) { tests := []struct { name string - config *Config + config *v1beta1.Config componentKinds []ComponentKind envVarsLen int }{ { name: "no env vars", - config: &Config{ - Receivers: AnyConfig{ + config: &v1beta1.Config{ + Receivers: v1beta1.AnyConfig{ Object: map[string]any{ "myreceiver": map[string]any{ "env": "test", }, }, }, - Service: Service{ - Pipelines: map[string]*Pipeline{ + Service: v1beta1.Service{ + Pipelines: map[string]*v1beta1.Pipeline{ "test": { Receivers: []string{"myreceiver"}, }, @@ -700,14 +704,14 @@ func TestConfig_getEnvironmentVariablesForComponentKinds(t *testing.T) { }, { name: "kubeletstats env vars", - config: &Config{ - Receivers: AnyConfig{ + config: &v1beta1.Config{ + Receivers: v1beta1.AnyConfig{ Object: map[string]any{ "kubeletstats": map[string]any{}, }, }, - Service: Service{ - Pipelines: map[string]*Pipeline{ + Service: v1beta1.Service{ + Pipelines: map[string]*v1beta1.Pipeline{ "test": { Receivers: []string{"kubeletstats"}, }, @@ -722,7 +726,7 @@ func TestConfig_getEnvironmentVariablesForComponentKinds(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { logger := logr.Discard() - envVars, err := tt.config.GetEnvironmentVariables(logger) + envVars, err := GetEnvironmentVariables(tt.config, logger) assert.NoError(t, err) assert.Len(t, envVars, tt.envVarsLen) @@ -739,7 +743,7 @@ func TestConfig_GetReceiverPorts(t *testing.T) { }{ { name: "k8sevents", - file: "testdata/otelcol-k8sevents.yaml", + file: path.Join(testdataPath, "otelcol-k8sevents.yaml"), want: []v1.ServicePort{ { Name: "otlp-http", @@ -749,22 +753,22 @@ func TestConfig_GetReceiverPorts(t *testing.T) { TargetPort: intstr.FromInt32(4318), }, }, - wantErr: false, // Silently fail + wantErr: false, }, { name: "connectors", - file: "testdata/otelcol-connectors.yaml", + file: path.Join(testdataPath, "otelcol-connectors.yaml"), want: nil, - wantErr: false, // Silently fail + wantErr: false, }, { name: "couchbase", - file: "testdata/otelcol-couchbase.yaml", - want: nil, // Couchbase uses a prometheus scraper, no ports should be opened + file: path.Join(testdataPath, "otelcol-couchbase.yaml"), + want: nil, }, { name: "demo", - file: "testdata/otelcol-demo.yaml", + file: path.Join(testdataPath, "otelcol-demo.yaml"), want: []v1.ServicePort{ { Name: "otlp-grpc", @@ -777,7 +781,7 @@ func TestConfig_GetReceiverPorts(t *testing.T) { }, { name: "extensions", - file: "testdata/otelcol-extensions.yaml", + file: path.Join(testdataPath, "otelcol-extensions.yaml"), want: []v1.ServicePort{ { Name: "otlp-grpc", @@ -790,12 +794,12 @@ func TestConfig_GetReceiverPorts(t *testing.T) { }, { name: "filelog", - file: "testdata/otelcol-filelog.yaml", + file: path.Join(testdataPath, "otelcol-filelog.yaml"), want: nil, }, { name: "null", - file: "testdata/otelcol-null-values.yaml", + file: path.Join(testdataPath, "otelcol-null-values.yaml"), want: nil, }, } @@ -804,10 +808,10 @@ func TestConfig_GetReceiverPorts(t *testing.T) { collectorYaml, err := os.ReadFile(tt.file) require.NoError(t, err) - c := &Config{} + c := &v1beta1.Config{} err = go_yaml.Unmarshal(collectorYaml, c) require.NoError(t, err) - ports, err := c.GetReceiverPorts(logr.Discard()) + ports, err := GetReceiverPorts(c, logr.Discard()) if tt.wantErr { require.Error(t, err) return @@ -827,13 +831,13 @@ func TestConfig_GetExporterPorts(t *testing.T) { }{ { name: "connectors", - file: "testdata/otelcol-connectors.yaml", + file: path.Join(testdataPath, "otelcol-connectors.yaml"), want: nil, wantErr: false, }, { name: "couchbase", - file: "testdata/otelcol-couchbase.yaml", + file: path.Join(testdataPath, "otelcol-couchbase.yaml"), want: []v1.ServicePort{ { Name: "prometheus", @@ -843,7 +847,7 @@ func TestConfig_GetExporterPorts(t *testing.T) { }, { name: "demo", - file: "testdata/otelcol-demo.yaml", + file: path.Join(testdataPath, "otelcol-demo.yaml"), want: []v1.ServicePort{ { Name: "prometheus", @@ -853,17 +857,17 @@ func TestConfig_GetExporterPorts(t *testing.T) { }, { name: "extensions", - file: "testdata/otelcol-extensions.yaml", + file: path.Join(testdataPath, "otelcol-extensions.yaml"), want: nil, }, { name: "filelog", - file: "testdata/otelcol-filelog.yaml", + file: path.Join(testdataPath, "otelcol-filelog.yaml"), want: nil, }, { name: "null", - file: "testdata/otelcol-null-values.yaml", + file: path.Join(testdataPath, "otelcol-null-values.yaml"), want: nil, }, } @@ -872,10 +876,10 @@ func TestConfig_GetExporterPorts(t *testing.T) { collectorYaml, err := os.ReadFile(tt.file) require.NoError(t, err) - c := &Config{} + c := &v1beta1.Config{} err = go_yaml.Unmarshal(collectorYaml, c) require.NoError(t, err) - ports, err := c.GetExporterPorts(logr.Discard()) + ports, err := GetExporterPorts(c, logr.Discard()) if tt.wantErr { require.Error(t, err) return @@ -889,15 +893,15 @@ func TestConfig_GetExporterPorts(t *testing.T) { func TestConfig_GetLivenessProbe(t *testing.T) { tests := []struct { name string - config *Config + config *v1beta1.Config wantProbe *v1.Probe wantErr bool }{ { name: "nil extensions should return nil", - config: &Config{ + config: &v1beta1.Config{ Extensions: nil, - Service: Service{ + Service: v1beta1.Service{ Extensions: []string{}, }, }, @@ -905,9 +909,9 @@ func TestConfig_GetLivenessProbe(t *testing.T) { }, { name: "nil extensions with health_check in service extensions should return nil", - config: &Config{ + config: &v1beta1.Config{ Extensions: nil, - Service: Service{ + Service: v1beta1.Service{ Extensions: []string{"health_check"}, }, }, @@ -915,11 +919,11 @@ func TestConfig_GetLivenessProbe(t *testing.T) { }, { name: "empty extensions should return nil", - config: &Config{ - Extensions: &AnyConfig{ + config: &v1beta1.Config{ + Extensions: &v1beta1.AnyConfig{ Object: map[string]any{}, }, - Service: Service{ + Service: v1beta1.Service{ Extensions: []string{}, }, }, @@ -927,11 +931,11 @@ func TestConfig_GetLivenessProbe(t *testing.T) { }, { name: "empty extensions with health_check in service extensions should return probe", - config: &Config{ - Extensions: &AnyConfig{ + config: &v1beta1.Config{ + Extensions: &v1beta1.AnyConfig{ Object: map[string]any{}, }, - Service: Service{ + Service: v1beta1.Service{ Extensions: []string{"health_check"}, }, }, @@ -946,13 +950,13 @@ func TestConfig_GetLivenessProbe(t *testing.T) { }, { name: "health_check extension enabled should return probe", - config: &Config{ - Extensions: &AnyConfig{ + config: &v1beta1.Config{ + Extensions: &v1beta1.AnyConfig{ Object: map[string]any{ "health_check": map[string]any{}, }, }, - Service: Service{ + Service: v1beta1.Service{ Extensions: []string{"health_check"}, }, }, @@ -967,15 +971,15 @@ func TestConfig_GetLivenessProbe(t *testing.T) { }, { name: "health_check extension with custom path", - config: &Config{ - Extensions: &AnyConfig{ + config: &v1beta1.Config{ + Extensions: &v1beta1.AnyConfig{ Object: map[string]any{ "health_check": map[string]any{ "path": "/healthz", }, }, }, - Service: Service{ + Service: v1beta1.Service{ Extensions: []string{"health_check"}, }, }, @@ -990,15 +994,15 @@ func TestConfig_GetLivenessProbe(t *testing.T) { }, { name: "health_check extension with custom endpoint port", - config: &Config{ - Extensions: &AnyConfig{ + config: &v1beta1.Config{ + Extensions: &v1beta1.AnyConfig{ Object: map[string]any{ "health_check": map[string]any{ "endpoint": "0.0.0.0:8080", }, }, }, - Service: Service{ + Service: v1beta1.Service{ Extensions: []string{"health_check"}, }, }, @@ -1013,13 +1017,13 @@ func TestConfig_GetLivenessProbe(t *testing.T) { }, { name: "extension without liveness probe should return nil", - config: &Config{ - Extensions: &AnyConfig{ + config: &v1beta1.Config{ + Extensions: &v1beta1.AnyConfig{ Object: map[string]any{ "jaeger_query": map[string]any{}, }, }, - Service: Service{ + Service: v1beta1.Service{ Extensions: []string{"jaeger_query"}, }, }, @@ -1027,13 +1031,13 @@ func TestConfig_GetLivenessProbe(t *testing.T) { }, { name: "invalid health_check config should return error", - config: &Config{ - Extensions: &AnyConfig{ + config: &v1beta1.Config{ + Extensions: &v1beta1.AnyConfig{ Object: map[string]any{ "health_check": func() {}, }, }, - Service: Service{ + Service: v1beta1.Service{ Extensions: []string{"health_check"}, }, }, @@ -1043,13 +1047,13 @@ func TestConfig_GetLivenessProbe(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := tt.config.GetLivenessProbe(logr.Discard()) + got, err := GetLivenessProbe(tt.config, logr.Discard()) if (err != nil) != tt.wantErr { - t.Errorf("Config.GetLivenessProbe() error = %v, wantErr %v", err, tt.wantErr) + t.Errorf("GetLivenessProbe() error = %v, wantErr %v", err, tt.wantErr) return } if diff := cmp.Diff(tt.wantProbe, got); diff != "" { - t.Errorf("Config.GetLivenessProbe() mismatch (-want +got):\n%s", diff) + t.Errorf("GetLivenessProbe() mismatch (-want +got):\n%s", diff) } }) } @@ -1058,15 +1062,15 @@ func TestConfig_GetLivenessProbe(t *testing.T) { func TestConfig_GetReadinessProbe(t *testing.T) { tests := []struct { name string - config *Config + config *v1beta1.Config wantProbe *v1.Probe wantErr bool }{ { name: "nil extensions should return nil", - config: &Config{ + config: &v1beta1.Config{ Extensions: nil, - Service: Service{ + Service: v1beta1.Service{ Extensions: []string{}, }, }, @@ -1074,9 +1078,9 @@ func TestConfig_GetReadinessProbe(t *testing.T) { }, { name: "nil extensions with health_check in service extensions should return nil", - config: &Config{ + config: &v1beta1.Config{ Extensions: nil, - Service: Service{ + Service: v1beta1.Service{ Extensions: []string{"health_check"}, }, }, @@ -1084,11 +1088,11 @@ func TestConfig_GetReadinessProbe(t *testing.T) { }, { name: "empty extensions should return nil", - config: &Config{ - Extensions: &AnyConfig{ + config: &v1beta1.Config{ + Extensions: &v1beta1.AnyConfig{ Object: map[string]any{}, }, - Service: Service{ + Service: v1beta1.Service{ Extensions: []string{}, }, }, @@ -1096,11 +1100,11 @@ func TestConfig_GetReadinessProbe(t *testing.T) { }, { name: "empty extensions with health_check in service extensions should return probe", - config: &Config{ - Extensions: &AnyConfig{ + config: &v1beta1.Config{ + Extensions: &v1beta1.AnyConfig{ Object: map[string]any{}, }, - Service: Service{ + Service: v1beta1.Service{ Extensions: []string{"health_check"}, }, }, @@ -1115,13 +1119,13 @@ func TestConfig_GetReadinessProbe(t *testing.T) { }, { name: "health_check extension enabled should return probe", - config: &Config{ - Extensions: &AnyConfig{ + config: &v1beta1.Config{ + Extensions: &v1beta1.AnyConfig{ Object: map[string]any{ "health_check": map[string]any{}, }, }, - Service: Service{ + Service: v1beta1.Service{ Extensions: []string{"health_check"}, }, }, @@ -1136,15 +1140,15 @@ func TestConfig_GetReadinessProbe(t *testing.T) { }, { name: "health_check extension with custom path", - config: &Config{ - Extensions: &AnyConfig{ + config: &v1beta1.Config{ + Extensions: &v1beta1.AnyConfig{ Object: map[string]any{ "health_check": map[string]any{ "path": "/healthz", }, }, }, - Service: Service{ + Service: v1beta1.Service{ Extensions: []string{"health_check"}, }, }, @@ -1159,15 +1163,15 @@ func TestConfig_GetReadinessProbe(t *testing.T) { }, { name: "health_check extension with custom endpoint port", - config: &Config{ - Extensions: &AnyConfig{ + config: &v1beta1.Config{ + Extensions: &v1beta1.AnyConfig{ Object: map[string]any{ "health_check": map[string]any{ "endpoint": "0.0.0.0:8080", }, }, }, - Service: Service{ + Service: v1beta1.Service{ Extensions: []string{"health_check"}, }, }, @@ -1182,13 +1186,13 @@ func TestConfig_GetReadinessProbe(t *testing.T) { }, { name: "extension without readiness probe should return nil", - config: &Config{ - Extensions: &AnyConfig{ + config: &v1beta1.Config{ + Extensions: &v1beta1.AnyConfig{ Object: map[string]any{ "jaeger_query": map[string]any{}, }, }, - Service: Service{ + Service: v1beta1.Service{ Extensions: []string{"jaeger_query"}, }, }, @@ -1196,13 +1200,13 @@ func TestConfig_GetReadinessProbe(t *testing.T) { }, { name: "invalid health_check config should return error", - config: &Config{ - Extensions: &AnyConfig{ + config: &v1beta1.Config{ + Extensions: &v1beta1.AnyConfig{ Object: map[string]any{ "health_check": func() {}, }, }, - Service: Service{ + Service: v1beta1.Service{ Extensions: []string{"health_check"}, }, }, @@ -1212,13 +1216,13 @@ func TestConfig_GetReadinessProbe(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := tt.config.GetReadinessProbe(logr.Discard()) + got, err := GetReadinessProbe(tt.config, logr.Discard()) if (err != nil) != tt.wantErr { - t.Errorf("Config.GetReadinessProbe() error = %v, wantErr %v", err, tt.wantErr) + t.Errorf("GetReadinessProbe() error = %v, wantErr %v", err, tt.wantErr) return } if diff := cmp.Diff(tt.wantProbe, got); diff != "" { - t.Errorf("Config.GetReadinessProbe() mismatch (-want +got):\n%s", diff) + t.Errorf("GetReadinessProbe() mismatch (-want +got):\n%s", diff) } }) } @@ -1227,15 +1231,15 @@ func TestConfig_GetReadinessProbe(t *testing.T) { func TestConfig_GetStartupProbe(t *testing.T) { tests := []struct { name string - config *Config + config *v1beta1.Config wantProbe *v1.Probe wantErr bool }{ { name: "nil extensions should return nil", - config: &Config{ + config: &v1beta1.Config{ Extensions: nil, - Service: Service{ + Service: v1beta1.Service{ Extensions: []string{}, }, }, @@ -1243,9 +1247,9 @@ func TestConfig_GetStartupProbe(t *testing.T) { }, { name: "nil extensions with health_check in service extensions should return nil", - config: &Config{ + config: &v1beta1.Config{ Extensions: nil, - Service: Service{ + Service: v1beta1.Service{ Extensions: []string{"health_check"}, }, }, @@ -1253,11 +1257,11 @@ func TestConfig_GetStartupProbe(t *testing.T) { }, { name: "empty extensions should return nil", - config: &Config{ - Extensions: &AnyConfig{ + config: &v1beta1.Config{ + Extensions: &v1beta1.AnyConfig{ Object: map[string]any{}, }, - Service: Service{ + Service: v1beta1.Service{ Extensions: []string{}, }, }, @@ -1265,11 +1269,11 @@ func TestConfig_GetStartupProbe(t *testing.T) { }, { name: "empty extensions with health_check in service extensions should return probe", - config: &Config{ - Extensions: &AnyConfig{ + config: &v1beta1.Config{ + Extensions: &v1beta1.AnyConfig{ Object: map[string]any{}, }, - Service: Service{ + Service: v1beta1.Service{ Extensions: []string{"health_check"}, }, }, @@ -1284,13 +1288,13 @@ func TestConfig_GetStartupProbe(t *testing.T) { }, { name: "health_check extension enabled should return probe", - config: &Config{ - Extensions: &AnyConfig{ + config: &v1beta1.Config{ + Extensions: &v1beta1.AnyConfig{ Object: map[string]any{ "health_check": map[string]any{}, }, }, - Service: Service{ + Service: v1beta1.Service{ Extensions: []string{"health_check"}, }, }, @@ -1305,15 +1309,15 @@ func TestConfig_GetStartupProbe(t *testing.T) { }, { name: "health_check extension with custom path", - config: &Config{ - Extensions: &AnyConfig{ + config: &v1beta1.Config{ + Extensions: &v1beta1.AnyConfig{ Object: map[string]any{ "health_check": map[string]any{ "path": "/healthz", }, }, }, - Service: Service{ + Service: v1beta1.Service{ Extensions: []string{"health_check"}, }, }, @@ -1328,15 +1332,15 @@ func TestConfig_GetStartupProbe(t *testing.T) { }, { name: "health_check extension with custom endpoint port", - config: &Config{ - Extensions: &AnyConfig{ + config: &v1beta1.Config{ + Extensions: &v1beta1.AnyConfig{ Object: map[string]any{ "health_check": map[string]any{ "endpoint": "0.0.0.0:8080", }, }, }, - Service: Service{ + Service: v1beta1.Service{ Extensions: []string{"health_check"}, }, }, @@ -1351,13 +1355,13 @@ func TestConfig_GetStartupProbe(t *testing.T) { }, { name: "extension without startup probe should return nil", - config: &Config{ - Extensions: &AnyConfig{ + config: &v1beta1.Config{ + Extensions: &v1beta1.AnyConfig{ Object: map[string]any{ "jaeger_query": map[string]any{}, }, }, - Service: Service{ + Service: v1beta1.Service{ Extensions: []string{"jaeger_query"}, }, }, @@ -1365,13 +1369,13 @@ func TestConfig_GetStartupProbe(t *testing.T) { }, { name: "invalid health_check config should return error", - config: &Config{ - Extensions: &AnyConfig{ + config: &v1beta1.Config{ + Extensions: &v1beta1.AnyConfig{ Object: map[string]any{ "health_check": func() {}, }, }, - Service: Service{ + Service: v1beta1.Service{ Extensions: []string{"health_check"}, }, }, @@ -1380,23 +1384,22 @@ func TestConfig_GetStartupProbe(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := tt.config.GetStartupProbe(logr.Discard()) + got, err := GetStartupProbe(tt.config, logr.Discard()) if (err != nil) != tt.wantErr { - t.Errorf("Config.GetStartupProbe() error = %v, wantErr %v", err, tt.wantErr) + t.Errorf("GetStartupProbe() error = %v, wantErr %v", err, tt.wantErr) return } if diff := cmp.Diff(tt.wantProbe, got); diff != "" { - t.Errorf("Config.GetStartupProbe() mismatch (-want +got):\n%s", diff) + t.Errorf("GetStartupProbe() mismatch (-want +got):\n%s", diff) } }) } } func TestTelemetryLogsPreservedWithMetrics(t *testing.T) { - // Test case where logs configuration exists and metrics is added - cfg := &Config{ - Service: Service{ - Telemetry: &AnyConfig{ + cfg := &v1beta1.Config{ + Service: v1beta1.Service{ + Telemetry: &v1beta1.AnyConfig{ Object: map[string]any{ "logs": map[string]any{ "level": "debug", @@ -1406,9 +1409,9 @@ func TestTelemetryLogsPreservedWithMetrics(t *testing.T) { }, } - expected := &Config{ - Service: Service{ - Telemetry: &AnyConfig{ + expected := &v1beta1.Config{ + Service: v1beta1.Service{ + Telemetry: &v1beta1.AnyConfig{ Object: map[string]any{ "logs": map[string]any{ "level": "debug", @@ -1432,19 +1435,19 @@ func TestTelemetryLogsPreservedWithMetrics(t *testing.T) { }, } - _, err := cfg.Service.ApplyDefaults(logr.Discard()) + _, err := ServiceApplyDefaults(&cfg.Service, logr.Discard()) require.NoError(t, err) logger := logr.Discard() - telemetry := cfg.Service.GetTelemetry(logger) + telemetry := GetTelemetry(&cfg.Service, logger) require.NotNil(t, telemetry) require.Equal(t, expected, cfg) } func TestTelemetryIncompleteConfigAppliesDefaults(t *testing.T) { - cfg := &Config{ - Service: Service{ - Telemetry: &AnyConfig{ + cfg := &v1beta1.Config{ + Service: v1beta1.Service{ + Telemetry: &v1beta1.AnyConfig{ Object: map[string]any{ "metrics": map[string]any{ "level": "basic", @@ -1454,7 +1457,6 @@ func TestTelemetryIncompleteConfigAppliesDefaults(t *testing.T) { "exporter": map[string]any{ "otlp": map[string]any{ "endpoint": "otlp_host:4317", - // Missing protocol - makes this invalid }, }, }, @@ -1466,11 +1468,11 @@ func TestTelemetryIncompleteConfigAppliesDefaults(t *testing.T) { }, } - _, err := cfg.Service.ApplyDefaults(logr.Discard()) + _, err := ServiceApplyDefaults(&cfg.Service, logr.Discard()) require.NoError(t, err) logger := logr.Discard() - telemetry := cfg.Service.GetTelemetry(logger) + telemetry := GetTelemetry(&cfg.Service, logger) require.NotNil(t, telemetry) require.Len(t, telemetry.Metrics.Readers, 1) @@ -1482,7 +1484,7 @@ func TestTelemetryIncompleteConfigAppliesDefaults(t *testing.T) { } func TestAnyConfigDeepCopyInto_NestedMapIndependence(t *testing.T) { - src := AnyConfig{Object: map[string]any{ + src := v1beta1.AnyConfig{Object: map[string]any{ "prometheus": map[string]any{ "config": map[string]any{ "scrape_configs": []any{ @@ -1500,34 +1502,31 @@ func TestAnyConfigDeepCopyInto_NestedMapIndependence(t *testing.T) { dst := src.DeepCopy() - // Mutate a nested map in the copy (simulates TLS profile injection). scrapeConfigs := dst.Object["prometheus"].(map[string]any)["config"].(map[string]any)["scrape_configs"].([]any) tlsConfig := scrapeConfigs[0].(map[string]any)["tls_config"].(map[string]any) tlsConfig["min_version"] = "TLS12" - // Source nested map must be unaffected. srcTLS := src.Object["prometheus"].(map[string]any)["config"].(map[string]any)["scrape_configs"].([]any)[0].(map[string]any)["tls_config"].(map[string]any) assert.NotContains(t, srcTLS, "min_version", "DeepCopy must produce independent nested maps; source was mutated through the copy") } func TestAnyConfigDeepCopyInto_NilObject(t *testing.T) { - src := AnyConfig{Object: nil} + src := v1beta1.AnyConfig{Object: nil} dst := src.DeepCopy() assert.Nil(t, dst.Object) } func TestAnyConfigDeepCopyInto_EmptyObject(t *testing.T) { - src := AnyConfig{Object: map[string]any{}} + src := v1beta1.AnyConfig{Object: map[string]any{}} dst := src.DeepCopy() assert.NotNil(t, dst.Object) assert.Empty(t, dst.Object) - // Mutating dst should not affect src. dst.Object["key"] = "value" assert.Empty(t, src.Object) } func TestAnyConfigDeepCopyInto_PreservesValues(t *testing.T) { - src := AnyConfig{Object: map[string]any{ + src := v1beta1.AnyConfig{Object: map[string]any{ "string_val": "hello", "number_val": float64(42), "bool_val": true, diff --git a/apis/v1beta1/helpers.go b/internal/apihelpers/v1beta1/helpers.go similarity index 98% rename from apis/v1beta1/helpers.go rename to internal/apihelpers/v1beta1/helpers.go index 61627c82ba..4bfe646e5c 100644 --- a/apis/v1beta1/helpers.go +++ b/internal/apihelpers/v1beta1/helpers.go @@ -1,7 +1,7 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -package v1beta1 +package apihelpers import ( "fmt" @@ -12,6 +12,8 @@ import ( "strings" ) +const defaultServicePort int32 = 8888 + // parseAddressEndpoint parses the address and returns the host and port. // If the address is an environment variable, it returns the default port. // If the address is an explicit port, it returns the port. diff --git a/apis/v1beta1/helpers_test.go b/internal/apihelpers/v1beta1/helpers_test.go similarity index 99% rename from apis/v1beta1/helpers_test.go rename to internal/apihelpers/v1beta1/helpers_test.go index 49e2b1234c..1601806ae2 100644 --- a/apis/v1beta1/helpers_test.go +++ b/internal/apihelpers/v1beta1/helpers_test.go @@ -1,7 +1,7 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -package v1beta1 +package apihelpers import ( "slices" diff --git a/apis/v1beta1/metrics.go b/internal/apihelpers/v1beta1/metrics.go similarity index 89% rename from apis/v1beta1/metrics.go rename to internal/apihelpers/v1beta1/metrics.go index a9cef0f5a0..f82e56a1b5 100644 --- a/apis/v1beta1/metrics.go +++ b/internal/apihelpers/v1beta1/metrics.go @@ -1,7 +1,7 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -package v1beta1 +package apihelpers import ( "context" @@ -14,6 +14,8 @@ import ( sdkmetric "go.opentelemetry.io/otel/sdk/metric" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/metrics" + + "github.com/open-telemetry/opentelemetry-operator/apis/v1beta1" ) const ( @@ -110,7 +112,7 @@ func NewMetrics(prv metric.MeterProvider, ctx context.Context, cl client.Reader) // Init metrics from the first time the operator starts. func (m *Metrics) init(ctx context.Context, cl client.Reader) error { - list := &OpenTelemetryCollectorList{} + list := &v1beta1.OpenTelemetryCollectorList{} if err := cl.List(ctx, list); err != nil { return fmt.Errorf("failed to list: %w", err) } @@ -121,22 +123,22 @@ func (m *Metrics) init(ctx context.Context, cl client.Reader) error { return nil } -func (m *Metrics) Create(ctx context.Context, collector *OpenTelemetryCollector) { +func (m *Metrics) Create(ctx context.Context, collector *v1beta1.OpenTelemetryCollector) { m.updateComponentCounters(ctx, collector, true) m.updateGeneralCRMetricsComponents(ctx, collector, true) } -func (m *Metrics) Delete(ctx context.Context, collector *OpenTelemetryCollector) { +func (m *Metrics) Delete(ctx context.Context, collector *v1beta1.OpenTelemetryCollector) { m.updateComponentCounters(ctx, collector, false) m.updateGeneralCRMetricsComponents(ctx, collector, false) } -func (m *Metrics) Update(ctx context.Context, oldCollector, newCollector *OpenTelemetryCollector) { +func (m *Metrics) Update(ctx context.Context, oldCollector, newCollector *v1beta1.OpenTelemetryCollector) { m.Delete(ctx, oldCollector) m.Create(ctx, newCollector) } -func (m *Metrics) updateGeneralCRMetricsComponents(ctx context.Context, collector *OpenTelemetryCollector, up bool) { +func (m *Metrics) updateGeneralCRMetricsComponents(ctx context.Context, collector *v1beta1.OpenTelemetryCollector, up bool) { inc := 1 if !up { inc = -1 @@ -148,7 +150,7 @@ func (m *Metrics) updateGeneralCRMetricsComponents(ctx context.Context, collecto )) } -func (m *Metrics) updateComponentCounters(ctx context.Context, collector *OpenTelemetryCollector, up bool) { +func (m *Metrics) updateComponentCounters(ctx context.Context, collector *v1beta1.OpenTelemetryCollector, up bool) { components := getComponentsFromConfig(collector.Spec.Config) moveCounter(ctx, collector, components.receivers, m.receiversCounter, up) moveCounter(ctx, collector, components.exporters, m.exporterCounter, up) @@ -176,7 +178,7 @@ func extractElements(elements map[string]any) []string { return items } -func getComponentsFromConfig(yamlContent Config) *componentDefinitions { +func getComponentsFromConfig(yamlContent v1beta1.Config) *componentDefinitions { info := &componentDefinitions{ receivers: extractElements(yamlContent.Receivers.Object), exporters: extractElements(yamlContent.Exporters.Object), @@ -198,7 +200,7 @@ func getComponentsFromConfig(yamlContent Config) *componentDefinitions { } func moveCounter( - ctx context.Context, collector *OpenTelemetryCollector, types []string, upDown metric.Int64UpDownCounter, up bool, + ctx context.Context, collector *v1beta1.OpenTelemetryCollector, types []string, upDown metric.Int64UpDownCounter, up bool, ) { for _, exporter := range types { inc := 1 diff --git a/apis/v1beta1/metrics_test.go b/internal/apihelpers/v1beta1/metrics_test.go similarity index 87% rename from apis/v1beta1/metrics_test.go rename to internal/apihelpers/v1beta1/metrics_test.go index 1de8af5005..c08ca4596a 100644 --- a/apis/v1beta1/metrics_test.go +++ b/internal/apihelpers/v1beta1/metrics_test.go @@ -1,7 +1,7 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -package v1beta1 +package apihelpers import ( "context" @@ -18,6 +18,8 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "sigs.k8s.io/controller-runtime/pkg/client/fake" + + "github.com/open-telemetry/opentelemetry-operator/apis/v1beta1" ) var wantInstrumentationScope = instrumentation.Scope{ @@ -25,21 +27,21 @@ var wantInstrumentationScope = instrumentation.Scope{ } func TestOTELCollectorCRDMetrics(t *testing.T) { - otelcollector1 := &OpenTelemetryCollector{ + otelcollector1 := &v1beta1.OpenTelemetryCollector{ ObjectMeta: metav1.ObjectMeta{ Name: "collector1", Namespace: "test1", }, - Spec: OpenTelemetryCollectorSpec{ - Mode: ModeDeployment, - Config: Config{ - Processors: &AnyConfig{ + Spec: v1beta1.OpenTelemetryCollectorSpec{ + Mode: v1beta1.ModeDeployment, + Config: v1beta1.Config{ + Processors: &v1beta1.AnyConfig{ Object: map[string]any{ "batch": nil, "foo": nil, }, }, - Extensions: &AnyConfig{ + Extensions: &v1beta1.AnyConfig{ Object: map[string]any{ "extfoo": nil, }, @@ -48,26 +50,26 @@ func TestOTELCollectorCRDMetrics(t *testing.T) { }, } - otelcollector2 := &OpenTelemetryCollector{ + otelcollector2 := &v1beta1.OpenTelemetryCollector{ ObjectMeta: metav1.ObjectMeta{ Name: "collector2", Namespace: "test2", }, - Spec: OpenTelemetryCollectorSpec{ - Mode: ModeSidecar, - Config: Config{ - Processors: &AnyConfig{ + Spec: v1beta1.OpenTelemetryCollectorSpec{ + Mode: v1beta1.ModeSidecar, + Config: v1beta1.Config{ + Processors: &v1beta1.AnyConfig{ Object: map[string]any{ "x": nil, "y": nil, }, }, - Extensions: &AnyConfig{ + Extensions: &v1beta1.AnyConfig{ Object: map[string]any{ "z/r": nil, }, }, - Exporters: AnyConfig{ + Exporters: v1beta1.AnyConfig{ Object: map[string]any{ "w": nil, }, @@ -76,26 +78,26 @@ func TestOTELCollectorCRDMetrics(t *testing.T) { }, } - updatedCollector1 := &OpenTelemetryCollector{ + updatedCollector1 := &v1beta1.OpenTelemetryCollector{ ObjectMeta: metav1.ObjectMeta{ Name: "collector1", Namespace: "test1", }, - Spec: OpenTelemetryCollectorSpec{ - Mode: ModeSidecar, - Config: Config{ - Processors: &AnyConfig{ + Spec: v1beta1.OpenTelemetryCollectorSpec{ + Mode: v1beta1.ModeSidecar, + Config: v1beta1.Config{ + Processors: &v1beta1.AnyConfig{ Object: map[string]any{ "foo": nil, "y": nil, }, }, - Extensions: &AnyConfig{ + Extensions: &v1beta1.AnyConfig{ Object: map[string]any{ "z/r": nil, }, }, - Exporters: AnyConfig{ + Exporters: v1beta1.AnyConfig{ Object: map[string]any{ "w": nil, }, @@ -106,7 +108,7 @@ func TestOTELCollectorCRDMetrics(t *testing.T) { tests := []struct { name string - testFunction func(t *testing.T, m *Metrics, collectors []*OpenTelemetryCollector, reader metric.Reader) + testFunction func(t *testing.T, m *Metrics, collectors []*v1beta1.OpenTelemetryCollector, reader metric.Reader) }{ { name: "Create", @@ -122,8 +124,8 @@ func TestOTELCollectorCRDMetrics(t *testing.T) { }, } schemeBuilder := runtime.NewSchemeBuilder(func(s *runtime.Scheme) error { - s.AddKnownTypes(GroupVersion, &OpenTelemetryCollector{}, &OpenTelemetryCollectorList{}) - metav1.AddToGroupVersion(s, GroupVersion) + s.AddKnownTypes(v1beta1.GroupVersion, &v1beta1.OpenTelemetryCollector{}, &v1beta1.OpenTelemetryCollectorList{}) + metav1.AddToGroupVersion(s, v1beta1.GroupVersion) return nil }) scheme := runtime.NewScheme() @@ -137,28 +139,28 @@ func TestOTELCollectorCRDMetrics(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - tt.testFunction(t, crdMetrics, []*OpenTelemetryCollector{otelcollector1, otelcollector2, updatedCollector1}, reader) + tt.testFunction(t, crdMetrics, []*v1beta1.OpenTelemetryCollector{otelcollector1, otelcollector2, updatedCollector1}, reader) }) } } func TestOTELCollectorInitMetrics(t *testing.T) { - otelcollector1 := OpenTelemetryCollector{ + otelcollector1 := v1beta1.OpenTelemetryCollector{ ObjectMeta: metav1.ObjectMeta{ Name: "collector1", Namespace: "test1", Labels: map[string]string{"app.kubernetes.io/managed-by": "opentelemetry-operator"}, }, - Spec: OpenTelemetryCollectorSpec{ - Mode: ModeDeployment, - Config: Config{ - Processors: &AnyConfig{ + Spec: v1beta1.OpenTelemetryCollectorSpec{ + Mode: v1beta1.ModeDeployment, + Config: v1beta1.Config{ + Processors: &v1beta1.AnyConfig{ Object: map[string]any{ "batch": nil, "foo": nil, }, }, - Extensions: &AnyConfig{ + Extensions: &v1beta1.AnyConfig{ Object: map[string]any{ "extfoo": nil, }, @@ -167,27 +169,27 @@ func TestOTELCollectorInitMetrics(t *testing.T) { }, } - otelcollector2 := OpenTelemetryCollector{ + otelcollector2 := v1beta1.OpenTelemetryCollector{ ObjectMeta: metav1.ObjectMeta{ Name: "collector2", Namespace: "test2", Labels: map[string]string{"app.kubernetes.io/managed-by": "opentelemetry-operator"}, }, - Spec: OpenTelemetryCollectorSpec{ - Mode: ModeSidecar, - Config: Config{ - Processors: &AnyConfig{ + Spec: v1beta1.OpenTelemetryCollectorSpec{ + Mode: v1beta1.ModeSidecar, + Config: v1beta1.Config{ + Processors: &v1beta1.AnyConfig{ Object: map[string]any{ "x": nil, "y": nil, }, }, - Extensions: &AnyConfig{ + Extensions: &v1beta1.AnyConfig{ Object: map[string]any{ "z/r": nil, }, }, - Exporters: AnyConfig{ + Exporters: v1beta1.AnyConfig{ Object: map[string]any{ "w": nil, }, @@ -197,15 +199,15 @@ func TestOTELCollectorInitMetrics(t *testing.T) { } schemeBuilder := runtime.NewSchemeBuilder(func(s *runtime.Scheme) error { - s.AddKnownTypes(GroupVersion, &OpenTelemetryCollector{}, &OpenTelemetryCollectorList{}) - metav1.AddToGroupVersion(s, GroupVersion) + s.AddKnownTypes(v1beta1.GroupVersion, &v1beta1.OpenTelemetryCollector{}, &v1beta1.OpenTelemetryCollectorList{}) + metav1.AddToGroupVersion(s, v1beta1.GroupVersion) return nil }) scheme := runtime.NewScheme() err := schemeBuilder.AddToScheme(scheme) require.NoError(t, err) - list := &OpenTelemetryCollectorList{ - Items: []OpenTelemetryCollector{otelcollector1, otelcollector2}, + list := &v1beta1.OpenTelemetryCollectorList{ + Items: []v1beta1.OpenTelemetryCollector{otelcollector1, otelcollector2}, } require.NoError(t, err, "Should be able to add custom types") cl := fake.NewClientBuilder().WithLists(list).WithScheme(scheme).Build() @@ -238,7 +240,7 @@ func TestOTELCollectorInitMetrics(t *testing.T) { Attributes: attribute.NewSet( attribute.Key("collector_name").String("collector2"), attribute.Key("namespace").String("test2"), - attribute.Key("type").String(string(ModeSidecar)), + attribute.Key("type").String(string(v1beta1.ModeSidecar)), ), Value: 1, }, @@ -332,7 +334,7 @@ func TestOTELCollectorInitMetrics(t *testing.T) { metricdatatest.AssertEqual(t, want, rm.ScopeMetrics[0], metricdatatest.IgnoreTimestamp()) } -func checkCreate(t *testing.T, m *Metrics, collectors []*OpenTelemetryCollector, reader metric.Reader) { +func checkCreate(t *testing.T, m *Metrics, collectors []*v1beta1.OpenTelemetryCollector, reader metric.Reader) { provider := metric.NewMeterProvider(metric.WithReader(reader)) otel.SetMeterProvider(provider) @@ -431,7 +433,7 @@ func checkCreate(t *testing.T, m *Metrics, collectors []*OpenTelemetryCollector, Attributes: attribute.NewSet( attribute.Key("collector_name").String("collector2"), attribute.Key("namespace").String("test2"), - attribute.Key("type").String(string(ModeSidecar)), + attribute.Key("type").String(string(v1beta1.ModeSidecar)), ), Value: 1, }, @@ -525,7 +527,7 @@ func checkCreate(t *testing.T, m *Metrics, collectors []*OpenTelemetryCollector, metricdatatest.AssertEqual(t, want, rm.ScopeMetrics[0], metricdatatest.IgnoreTimestamp()) } -func checkUpdate(t *testing.T, m *Metrics, collectors []*OpenTelemetryCollector, reader metric.Reader) { +func checkUpdate(t *testing.T, m *Metrics, collectors []*v1beta1.OpenTelemetryCollector, reader metric.Reader) { m.Update(context.Background(), collectors[0], collectors[2]) rm := metricdata.ResourceMetrics{} @@ -544,7 +546,7 @@ func checkUpdate(t *testing.T, m *Metrics, collectors []*OpenTelemetryCollector, Attributes: attribute.NewSet( attribute.Key("collector_name").String("collector1"), attribute.Key("namespace").String("test1"), - attribute.Key("type").String(string(ModeDeployment)), + attribute.Key("type").String(string(v1beta1.ModeDeployment)), ), Value: 0, }, @@ -552,7 +554,7 @@ func checkUpdate(t *testing.T, m *Metrics, collectors []*OpenTelemetryCollector, Attributes: attribute.NewSet( attribute.Key("collector_name").String("collector1"), attribute.Key("namespace").String("test1"), - attribute.Key("type").String(string(ModeSidecar)), + attribute.Key("type").String(string(v1beta1.ModeSidecar)), ), Value: 1, }, @@ -560,7 +562,7 @@ func checkUpdate(t *testing.T, m *Metrics, collectors []*OpenTelemetryCollector, Attributes: attribute.NewSet( attribute.Key("collector_name").String("collector2"), attribute.Key("namespace").String("test2"), - attribute.Key("type").String(string(ModeSidecar)), + attribute.Key("type").String(string(v1beta1.ModeSidecar)), ), Value: 1, }, @@ -677,7 +679,7 @@ func checkUpdate(t *testing.T, m *Metrics, collectors []*OpenTelemetryCollector, metricdatatest.AssertEqual(t, want, rm.ScopeMetrics[0], metricdatatest.IgnoreTimestamp()) } -func checkDelete(t *testing.T, m *Metrics, collectors []*OpenTelemetryCollector, reader metric.Reader) { +func checkDelete(t *testing.T, m *Metrics, collectors []*v1beta1.OpenTelemetryCollector, reader metric.Reader) { m.Delete(context.Background(), collectors[1]) rm := metricdata.ResourceMetrics{} err := reader.Collect(context.Background(), &rm) @@ -694,7 +696,7 @@ func checkDelete(t *testing.T, m *Metrics, collectors []*OpenTelemetryCollector, Attributes: attribute.NewSet( attribute.Key("collector_name").String("collector1"), attribute.Key("namespace").String("test1"), - attribute.Key("type").String(string(ModeDeployment)), + attribute.Key("type").String(string(v1beta1.ModeDeployment)), ), Value: 0, }, @@ -702,7 +704,7 @@ func checkDelete(t *testing.T, m *Metrics, collectors []*OpenTelemetryCollector, Attributes: attribute.NewSet( attribute.Key("collector_name").String("collector1"), attribute.Key("namespace").String("test1"), - attribute.Key("type").String(string(ModeSidecar)), + attribute.Key("type").String(string(v1beta1.ModeSidecar)), ), Value: 1, }, @@ -710,7 +712,7 @@ func checkDelete(t *testing.T, m *Metrics, collectors []*OpenTelemetryCollector, Attributes: attribute.NewSet( attribute.Key("collector_name").String("collector2"), attribute.Key("namespace").String("test2"), - attribute.Key("type").String(string(ModeSidecar)), + attribute.Key("type").String(string(v1beta1.ModeSidecar)), ), Value: 0, }, diff --git a/apis/v1beta1/targetallocator_rbac.go b/internal/apihelpers/v1beta1/targetallocator_rbac.go similarity index 98% rename from apis/v1beta1/targetallocator_rbac.go rename to internal/apihelpers/v1beta1/targetallocator_rbac.go index 19063558c8..65c2910123 100644 --- a/apis/v1beta1/targetallocator_rbac.go +++ b/internal/apihelpers/v1beta1/targetallocator_rbac.go @@ -1,7 +1,7 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -package v1beta1 +package apihelpers import ( "context" diff --git a/internal/manifests/collector/config_replace.go b/internal/manifests/collector/config_replace.go index 2dfc636296..ddb5e07a8e 100644 --- a/internal/manifests/collector/config_replace.go +++ b/internal/manifests/collector/config_replace.go @@ -8,6 +8,7 @@ import ( "github.com/open-telemetry/opentelemetry-operator/apis/v1alpha1" "github.com/open-telemetry/opentelemetry-operator/apis/v1beta1" + apihelpers "github.com/open-telemetry/opentelemetry-operator/internal/apihelpers/v1beta1" "github.com/open-telemetry/opentelemetry-operator/internal/manifests/collector/adapters" ta "github.com/open-telemetry/opentelemetry-operator/internal/manifests/targetallocator/adapters" "github.com/open-telemetry/opentelemetry-operator/internal/naming" @@ -16,7 +17,7 @@ import ( func ReplaceConfig(otelcol v1beta1.OpenTelemetryCollector, targetAllocator *v1alpha1.TargetAllocator, options ...ta.TAOption) (string, error) { collectorSpec := otelcol.Spec taEnabled := targetAllocator != nil - cfgStr, err := collectorSpec.Config.Yaml() + cfgStr, err := apihelpers.Yaml(&collectorSpec.Config) if err != nil { return "", err } diff --git a/internal/manifests/collector/configmap.go b/internal/manifests/collector/configmap.go index cdc5a156e1..02e5f2cf3b 100644 --- a/internal/manifests/collector/configmap.go +++ b/internal/manifests/collector/configmap.go @@ -9,6 +9,7 @@ import ( corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + apihelpers "github.com/open-telemetry/opentelemetry-operator/internal/apihelpers/v1beta1" "github.com/open-telemetry/opentelemetry-operator/internal/autodetect/certmanager" "github.com/open-telemetry/opentelemetry-operator/internal/components" "github.com/open-telemetry/opentelemetry-operator/internal/manifests" @@ -27,7 +28,7 @@ func ConfigMap(params manifests.Params) (*corev1.ConfigMap, error) { // This ensures collectors get updated TLS settings when the operator restarts // after a cluster TLS profile change, without requiring CR updates. if params.Config.Internal.OperandTLSProfile != nil { - _, err := otelCol.Spec.Config.ApplyDefaults(params.Log, components.WithTLSProfile(params.Config.Internal.OperandTLSProfile)) + _, err := apihelpers.ApplyDefaults(&otelCol.Spec.Config, params.Log, components.WithTLSProfile(params.Config.Internal.OperandTLSProfile)) if err != nil { params.Log.Error(err, "failed to apply TLS defaults to collector config") return nil, err diff --git a/internal/manifests/collector/container.go b/internal/manifests/collector/container.go index 5013ea7000..bc98400860 100644 --- a/internal/manifests/collector/container.go +++ b/internal/manifests/collector/container.go @@ -17,6 +17,7 @@ import ( "github.com/open-telemetry/opentelemetry-operator/apis/v1beta1" "github.com/open-telemetry/opentelemetry-operator/internal/autodetect/certmanager" "github.com/open-telemetry/opentelemetry-operator/internal/config" + apihelpers "github.com/open-telemetry/opentelemetry-operator/internal/apihelpers/v1beta1" "github.com/open-telemetry/opentelemetry-operator/internal/naming" "github.com/open-telemetry/opentelemetry-operator/pkg/constants" "github.com/open-telemetry/opentelemetry-operator/pkg/featuregate" @@ -93,19 +94,19 @@ func Container(cfg config.Config, logger logr.Logger, otelcol v1beta1.OpenTeleme } } - livenessProbe, livenessProbeErr := otelcol.Spec.Config.GetLivenessProbe(logger) + livenessProbe, livenessProbeErr := apihelpers.GetLivenessProbe(&otelcol.Spec.Config, logger) if livenessProbeErr != nil { logger.Error(livenessProbeErr, "cannot create liveness probe.") } else { defaultProbeSettings(livenessProbe, otelcol.Spec.LivenessProbe) } - readinessProbe, readinessProbeErr := otelcol.Spec.Config.GetReadinessProbe(logger) + readinessProbe, readinessProbeErr := apihelpers.GetReadinessProbe(&otelcol.Spec.Config, logger) if readinessProbeErr != nil { logger.Error(readinessProbeErr, "cannot create readiness probe.") } else { defaultProbeSettings(readinessProbe, otelcol.Spec.ReadinessProbe) } - startupProbe, startupProbeErr := otelcol.Spec.Config.GetStartupProbe(logger) + startupProbe, startupProbeErr := apihelpers.GetStartupProbe(&otelcol.Spec.Config, logger) if startupProbeErr != nil { logger.Error(startupProbeErr, "cannot create startup probe.") } else { @@ -132,7 +133,7 @@ func Container(cfg config.Config, logger logr.Logger, otelcol v1beta1.OpenTeleme func getConfigContainerPorts(logger logr.Logger, conf v1beta1.Config) ([]corev1.ContainerPort, error) { ports := []corev1.ContainerPort{} - ps, err := conf.GetAllPorts(logger) + ps, err := apihelpers.GetAllPorts(&conf, logger) if err != nil { return ports, err } @@ -158,7 +159,7 @@ func getConfigContainerPorts(logger logr.Logger, conf v1beta1.Config) ([]corev1. } } - _, metricsPort, err := conf.Service.MetricsEndpoint(logger) + _, metricsPort, err := apihelpers.MetricsEndpoint(&conf.Service, logger) if err != nil { logger.Info("couldn't determine metrics port from configuration, using 8888 default value", "error", err) metricsPort = 8888 @@ -357,7 +358,7 @@ func getInferredContainerEnvVars(otelcol v1beta1.OpenTelemetryCollector, logger ) } - if configEnvVars, err := otelcol.Spec.Config.GetEnvironmentVariables(logger); err != nil { + if configEnvVars, err := apihelpers.GetEnvironmentVariables(&otelcol.Spec.Config, logger); err != nil { logger.Error(err, "could not get the environment variables from the config") } else { envVars = append(envVars, configEnvVars...) diff --git a/internal/manifests/collector/ingress.go b/internal/manifests/collector/ingress.go index 9e7ce8f9bd..fac74748a6 100644 --- a/internal/manifests/collector/ingress.go +++ b/internal/manifests/collector/ingress.go @@ -12,6 +12,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "github.com/open-telemetry/opentelemetry-operator/apis/v1beta1" + apihelpers "github.com/open-telemetry/opentelemetry-operator/internal/apihelpers/v1beta1" "github.com/open-telemetry/opentelemetry-operator/internal/manifests" "github.com/open-telemetry/opentelemetry-operator/internal/manifests/manifestutils" "github.com/open-telemetry/opentelemetry-operator/internal/naming" @@ -124,7 +125,7 @@ func createSubdomainIngressRules(otelcol, hostname string, ports []corev1.Servic } func servicePortsFromCfg(logger logr.Logger, otelcol v1beta1.OpenTelemetryCollector) ([]corev1.ServicePort, error) { - ports, err := otelcol.Spec.Config.GetReceiverPorts(logger) + ports, err := apihelpers.GetReceiverPorts(&otelcol.Spec.Config, logger) if err != nil { logger.Error(err, "couldn't build the ingress for this instance") return nil, err diff --git a/internal/manifests/collector/podmonitor.go b/internal/manifests/collector/podmonitor.go index df15c3bfa1..08e4155443 100644 --- a/internal/manifests/collector/podmonitor.go +++ b/internal/manifests/collector/podmonitor.go @@ -12,6 +12,7 @@ import ( "github.com/open-telemetry/opentelemetry-operator/apis/v1beta1" "github.com/open-telemetry/opentelemetry-operator/internal/autodetect/prometheus" + apihelpers "github.com/open-telemetry/opentelemetry-operator/internal/apihelpers/v1beta1" "github.com/open-telemetry/opentelemetry-operator/internal/manifests" "github.com/open-telemetry/opentelemetry-operator/internal/manifests/manifestutils" "github.com/open-telemetry/opentelemetry-operator/internal/naming" @@ -56,7 +57,7 @@ func PodMonitor(params manifests.Params) (*monitoringv1.PodMonitor, error) { } func metricsEndpointsFromConfig(logger logr.Logger, otelcol v1beta1.OpenTelemetryCollector) []monitoringv1.PodMetricsEndpoint { - exporterPorts, err := otelcol.Spec.Config.GetExporterPorts(logger) + exporterPorts, err := apihelpers.GetExporterPorts(&otelcol.Spec.Config, logger) if err != nil { logger.Error(err, "couldn't build endpoints to podMonitors from configuration") return []monitoringv1.PodMetricsEndpoint{} diff --git a/internal/manifests/collector/rbac.go b/internal/manifests/collector/rbac.go index ad3ec07aab..505f87f3c7 100644 --- a/internal/manifests/collector/rbac.go +++ b/internal/manifests/collector/rbac.go @@ -10,6 +10,7 @@ import ( rbacv1 "k8s.io/api/rbac/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + apihelpers "github.com/open-telemetry/opentelemetry-operator/internal/apihelpers/v1beta1" "github.com/open-telemetry/opentelemetry-operator/internal/manifests" "github.com/open-telemetry/opentelemetry-operator/internal/manifests/manifestutils" "github.com/open-telemetry/opentelemetry-operator/internal/naming" @@ -17,7 +18,7 @@ import ( ) func ClusterRole(params manifests.Params) (*rbacv1.ClusterRole, error) { - rules, err := params.OtelCol.Spec.Config.GetAllRbacRules(params.Log) + rules, err := apihelpers.GetAllRbacRules(¶ms.OtelCol.Spec.Config, params.Log) if err != nil { return nil, err } else if len(rules) == 0 { @@ -43,7 +44,7 @@ func ClusterRole(params manifests.Params) (*rbacv1.ClusterRole, error) { } func ClusterRoleBinding(params manifests.Params) (*rbacv1.ClusterRoleBinding, error) { - rules, err := params.OtelCol.Spec.Config.GetAllRbacRules(params.Log) + rules, err := apihelpers.GetAllRbacRules(¶ms.OtelCol.Spec.Config, params.Log) if err != nil { return nil, err } else if len(rules) == 0 { @@ -82,7 +83,7 @@ func ClusterRoleBinding(params manifests.Params) (*rbacv1.ClusterRoleBinding, er func CheckRbacRules(params manifests.Params, saName string) ([]string, error) { ctx := context.Background() - rules, err := params.OtelCol.Spec.Config.GetAllRbacRules(params.Log) + rules, err := apihelpers.GetAllRbacRules(¶ms.OtelCol.Spec.Config, params.Log) if err != nil { return nil, err } diff --git a/internal/manifests/collector/service.go b/internal/manifests/collector/service.go index e4bb749b2e..df4131c86d 100644 --- a/internal/manifests/collector/service.go +++ b/internal/manifests/collector/service.go @@ -13,6 +13,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "github.com/open-telemetry/opentelemetry-operator/apis/v1beta1" + apihelpers "github.com/open-telemetry/opentelemetry-operator/internal/apihelpers/v1beta1" "github.com/open-telemetry/opentelemetry-operator/internal/manifests" "github.com/open-telemetry/opentelemetry-operator/internal/manifests/manifestutils" "github.com/open-telemetry/opentelemetry-operator/internal/naming" @@ -71,7 +72,7 @@ func MonitoringService(params manifests.Params) (*corev1.Service, error) { return nil, err } - _, metricsPort, err := params.OtelCol.Spec.Config.Service.MetricsEndpoint(params.Log) + _, metricsPort, err := apihelpers.MetricsEndpoint(¶ms.OtelCol.Spec.Config.Service, params.Log) if err != nil { return nil, err } @@ -107,7 +108,7 @@ func ExtensionService(params manifests.Params) (*corev1.Service, error) { return nil, err } - ports, err := params.OtelCol.Spec.Config.GetExtensionPorts(params.Log) + ports, err := apihelpers.GetExtensionPorts(¶ms.OtelCol.Spec.Config, params.Log) if err != nil { return nil, err } @@ -141,7 +142,7 @@ func Service(params manifests.Params) (*corev1.Service, error) { return nil, err } - ports, err := params.OtelCol.Spec.Config.GetReceiverAndExporterPorts(params.Log) + ports, err := apihelpers.GetReceiverAndExporterPorts(¶ms.OtelCol.Spec.Config, params.Log) if err != nil { return nil, err } diff --git a/internal/manifests/collector/servicemonitor.go b/internal/manifests/collector/servicemonitor.go index 7e5180eaf0..79b1d85399 100644 --- a/internal/manifests/collector/servicemonitor.go +++ b/internal/manifests/collector/servicemonitor.go @@ -13,6 +13,7 @@ import ( "github.com/open-telemetry/opentelemetry-operator/apis/v1beta1" "github.com/open-telemetry/opentelemetry-operator/internal/autodetect/prometheus" + apihelpers "github.com/open-telemetry/opentelemetry-operator/internal/apihelpers/v1beta1" "github.com/open-telemetry/opentelemetry-operator/internal/manifests" "github.com/open-telemetry/opentelemetry-operator/internal/manifests/manifestutils" "github.com/open-telemetry/opentelemetry-operator/internal/naming" @@ -96,7 +97,7 @@ func shouldCreateServiceMonitor(params manifests.Params) bool { } func endpointsFromConfig(logger logr.Logger, otelcol v1beta1.OpenTelemetryCollector) []monitoringv1.Endpoint { - exporterPorts, err := otelcol.Spec.Config.GetExporterPorts(logger) + exporterPorts, err := apihelpers.GetExporterPorts(&otelcol.Spec.Config, logger) if err != nil { logger.Error(err, "couldn't build service monitors from configuration") return []monitoringv1.Endpoint{} diff --git a/internal/manifests/collector/volume.go b/internal/manifests/collector/volume.go index 75375ebcec..0ac6cc30a4 100644 --- a/internal/manifests/collector/volume.go +++ b/internal/manifests/collector/volume.go @@ -9,6 +9,7 @@ import ( corev1 "k8s.io/api/core/v1" "github.com/open-telemetry/opentelemetry-operator/apis/v1beta1" + apihelpers "github.com/open-telemetry/opentelemetry-operator/internal/apihelpers/v1beta1" "github.com/open-telemetry/opentelemetry-operator/internal/autodetect/certmanager" "github.com/open-telemetry/opentelemetry-operator/internal/components" "github.com/open-telemetry/opentelemetry-operator/internal/config" @@ -21,7 +22,7 @@ import ( func Volumes(cfg config.Config, otelcol v1beta1.OpenTelemetryCollector) []corev1.Volume { collectorCfg := otelcol.Spec.Config.DeepCopy() if cfg.Internal.OperandTLSProfile != nil { - _, _ = collectorCfg.ApplyDefaults(logr.Discard(), components.WithTLSProfile(cfg.Internal.OperandTLSProfile)) + _, _ = apihelpers.ApplyDefaults(collectorCfg, logr.Discard(), components.WithTLSProfile(cfg.Internal.OperandTLSProfile)) } hash, _ := manifestutils.GetConfigMapSHA(*collectorCfg) configMapName := naming.ConfigMap(otelcol.Name, hash) diff --git a/internal/manifests/targetallocator/configmap.go b/internal/manifests/targetallocator/configmap.go index 73a1f7e6d0..2b9c578a33 100644 --- a/internal/manifests/targetallocator/configmap.go +++ b/internal/manifests/targetallocator/configmap.go @@ -12,6 +12,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "github.com/open-telemetry/opentelemetry-operator/apis/v1beta1" + apihelpers "github.com/open-telemetry/opentelemetry-operator/internal/apihelpers/v1beta1" "github.com/open-telemetry/opentelemetry-operator/internal/autodetect/certmanager" "github.com/open-telemetry/opentelemetry-operator/internal/manifests/collector" "github.com/open-telemetry/opentelemetry-operator/internal/manifests/manifestutils" @@ -180,7 +181,7 @@ func getScrapeConfigs(taScrapeConfigs []v1beta1.AnyConfig, collectorConfig v1bet scrapeConfigs = append(scrapeConfigs, taScrapeConfigs...) } - configStr, err := collectorConfig.Yaml() + configStr, err := apihelpers.Yaml(&collectorConfig) if err != nil { return nil, err } diff --git a/internal/manifests/targetallocator/configmap_test.go b/internal/manifests/targetallocator/configmap_test.go index 1ce8630012..c693f45664 100644 --- a/internal/manifests/targetallocator/configmap_test.go +++ b/internal/manifests/targetallocator/configmap_test.go @@ -16,6 +16,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "github.com/open-telemetry/opentelemetry-operator/apis/v1beta1" + apihelpers "github.com/open-telemetry/opentelemetry-operator/internal/apihelpers/v1beta1" "github.com/open-telemetry/opentelemetry-operator/internal/autodetect/certmanager" "github.com/open-telemetry/opentelemetry-operator/internal/config" "github.com/open-telemetry/opentelemetry-operator/pkg/featuregate" @@ -617,7 +618,7 @@ func TestGetScrapeConfigsFromOtelConfig(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { - configStr, err := testCase.input.Yaml() + configStr, err := apihelpers.Yaml(&testCase.input) require.NoError(t, err) actual, err := getScrapeConfigsFromOtelConfig(configStr) assert.Equal(t, testCase.wantErr, err) diff --git a/internal/webhook/collector_webhook.go b/internal/webhook/collector_webhook.go index 1b599a685d..2371c95004 100644 --- a/internal/webhook/collector_webhook.go +++ b/internal/webhook/collector_webhook.go @@ -23,6 +23,7 @@ import ( ta "github.com/open-telemetry/opentelemetry-operator/internal/manifests/targetallocator/adapters" "github.com/open-telemetry/opentelemetry-operator/internal/naming" "github.com/open-telemetry/opentelemetry-operator/internal/rbac" + apihelpers "github.com/open-telemetry/opentelemetry-operator/internal/apihelpers/v1beta1" "github.com/open-telemetry/opentelemetry-operator/pkg/featuregate" ) @@ -45,7 +46,7 @@ type CollectorWebhook struct { cfg config.Config scheme *runtime.Scheme reviewer *rbac.Reviewer - metrics *v1beta1.Metrics + metrics *apihelpers.Metrics bv BuildValidator fips fips.FIPSCheck recorder events.EventRecorder @@ -103,7 +104,7 @@ func (c CollectorWebhook) Default(_ context.Context, otelcol *v1beta1.OpenTeleme // TLS defaults are applied at reconciliation time (ConfigMap generation) so that // existing collectors automatically get updated TLS settings when the operator // restarts after a cluster TLS profile change. - events, err := otelcol.Spec.Config.ApplyDefaults(c.logger) + events, err := apihelpers.ApplyDefaults(&otelcol.Spec.Config, c.logger) if err != nil { return err } @@ -166,7 +167,7 @@ func (c CollectorWebhook) ValidateDelete(ctx context.Context, otelcol *v1beta1.O func (c CollectorWebhook) Validate(ctx context.Context, r *v1beta1.OpenTelemetryCollector) (admission.Warnings, error) { warnings := admission.Warnings{} - nullObjects := r.Spec.Config.NullObjects() + nullObjects := apihelpers.NullObjects(&r.Spec.Config) if len(nullObjects) > 0 { warnings = append(warnings, fmt.Sprintf("Collector config spec.config has null objects: %s. For compatibility with other tooling, such as kustomize and kubectl edit, it is recommended to use empty objects e.g. batch: {}.", strings.Join(nullObjects, ", "))) } @@ -219,7 +220,7 @@ func (c CollectorWebhook) Validate(ctx context.Context, r *v1beta1.OpenTelemetry if err := ValidatePorts(r.Spec.Ports); err != nil { return warnings, err } - ports, errPorts := r.Spec.Config.GetAllPorts(c.logger) + ports, errPorts := apihelpers.GetAllPorts(&r.Spec.Config, c.logger) if errPorts != nil { return warnings, fmt.Errorf("the OpenTelemetry config is incorrect. The port numbers are invalid: %w", errPorts) } @@ -294,8 +295,8 @@ func (c CollectorWebhook) Validate(ctx context.Context, r *v1beta1.OpenTelemetry } if c.fips != nil { - components := r.Spec.Config.GetEnabledComponents() - if notAllowedComponents := c.fips.DisabledComponents(components[v1beta1.KindReceiver], components[v1beta1.KindExporter], components[v1beta1.KindProcessor], components[v1beta1.KindExtension]); notAllowedComponents != nil { + components := apihelpers.GetEnabledComponents(&r.Spec.Config) + if notAllowedComponents := c.fips.DisabledComponents(components[apihelpers.KindReceiver], components[apihelpers.KindExporter], components[apihelpers.KindProcessor], components[apihelpers.KindExtension]); notAllowedComponents != nil { return nil, fmt.Errorf("the collector configuration contains not FIPS compliant components: %s. Please remove it from the config", notAllowedComponents) } } @@ -316,7 +317,7 @@ func (c CollectorWebhook) validateTargetAllocatorConfig(ctx context.Context, r * return nil, fmt.Errorf("target allocation strategy %s is only supported in OpenTelemetry Collector mode %s", v1beta1.TargetAllocatorAllocationStrategyPerNode, v1beta1.ModeDaemonSet) } - cfgYaml, err := r.Spec.Config.Yaml() + cfgYaml, err := apihelpers.Yaml(&r.Spec.Config) if err != nil { return nil, err } @@ -339,7 +340,7 @@ func (c CollectorWebhook) validateTargetAllocatorConfig(ctx context.Context, r * if r.Spec.TargetAllocator.ServiceAccount == "" { saname = naming.TargetAllocatorServiceAccount(r.Name) } - warnings, err := v1beta1.CheckTargetAllocatorPrometheusCRPolicyRules( + warnings, err := apihelpers.CheckTargetAllocatorPrometheusCRPolicyRules( ctx, c.reviewer, r.GetNamespace(), saname) if err != nil || len(warnings) > 0 { return warnings, err @@ -407,7 +408,7 @@ func NewCollectorWebhook( cfg config.Config, reviewer *rbac.Reviewer, recorder events.EventRecorder, - metrics *v1beta1.Metrics, + metrics *apihelpers.Metrics, bv BuildValidator, fips fips.FIPSCheck, ) *CollectorWebhook { @@ -423,7 +424,7 @@ func NewCollectorWebhook( } } -func SetupCollectorWebhook(mgr ctrl.Manager, cfg config.Config, reviewer *rbac.Reviewer, metrics *v1beta1.Metrics, bv BuildValidator, fipsCheck fips.FIPSCheck) error { +func SetupCollectorWebhook(mgr ctrl.Manager, cfg config.Config, reviewer *rbac.Reviewer, metrics *apihelpers.Metrics, bv BuildValidator, fipsCheck fips.FIPSCheck) error { cvw := NewCollectorWebhook(mgr.GetLogger().WithValues("handler", "CollectorWebhook", "version", "v1beta1"), mgr.GetScheme(), cfg, reviewer, mgr.GetEventRecorder("opentelemetry-operator"), metrics, bv, fipsCheck) return ctrl.NewWebhookManagedBy(mgr, &v1beta1.OpenTelemetryCollector{}). WithValidator(cvw). diff --git a/internal/webhook/collector_webhook_test.go b/internal/webhook/collector_webhook_test.go index 5aa6f25266..317bf9679c 100644 --- a/internal/webhook/collector_webhook_test.go +++ b/internal/webhook/collector_webhook_test.go @@ -31,6 +31,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/webhook/admission" "github.com/open-telemetry/opentelemetry-operator/apis/v1beta1" + apihelpers "github.com/open-telemetry/opentelemetry-operator/internal/apihelpers/v1beta1" "github.com/open-telemetry/opentelemetry-operator/internal/config" "github.com/open-telemetry/opentelemetry-operator/internal/manifests" collectorManifests "github.com/open-telemetry/opentelemetry-operator/internal/manifests/collector" @@ -551,7 +552,7 @@ func TestCollectorDefaultingWebhook(t *testing.T) { ctx := context.Background() err := cvw.Default(ctx, &test.otelcol) if test.expected.Spec.Config.Service.Telemetry == nil { - _, applyErr := test.expected.Spec.Config.Service.ApplyDefaults(logr.Discard()) + _, applyErr := apihelpers.ServiceApplyDefaults(&test.expected.Spec.Config.Service, logr.Discard()) assert.NoError(t, applyErr, "could not apply defaults") } assert.NoError(t, err) diff --git a/internal/webhook/targetallocator_webhook.go b/internal/webhook/targetallocator_webhook.go index 0a011f88f6..510c55b3b2 100644 --- a/internal/webhook/targetallocator_webhook.go +++ b/internal/webhook/targetallocator_webhook.go @@ -15,6 +15,7 @@ import ( "github.com/open-telemetry/opentelemetry-operator/apis/v1alpha1" "github.com/open-telemetry/opentelemetry-operator/apis/v1beta1" + apihelpers "github.com/open-telemetry/opentelemetry-operator/internal/apihelpers/v1beta1" "github.com/open-telemetry/opentelemetry-operator/internal/config" "github.com/open-telemetry/opentelemetry-operator/internal/naming" "github.com/open-telemetry/opentelemetry-operator/internal/rbac" @@ -102,7 +103,7 @@ func (w TargetAllocatorWebhook) validate(ctx context.Context, ta *v1alpha1.Targe if ta.Spec.ServiceAccount == "" { saname = naming.TargetAllocatorServiceAccount(ta.Name) } - warnings, err := v1beta1.CheckTargetAllocatorPrometheusCRPolicyRules(ctx, w.reviewer, ta.GetNamespace(), saname) + warnings, err := apihelpers.CheckTargetAllocatorPrometheusCRPolicyRules(ctx, w.reviewer, ta.GetNamespace(), saname) if err != nil || len(warnings) > 0 { return warnings, err } diff --git a/main.go b/main.go index e05c77452f..2899a9c80c 100644 --- a/main.go +++ b/main.go @@ -53,6 +53,7 @@ import ( "github.com/open-telemetry/opentelemetry-operator/internal/autodetect/openshift" "github.com/open-telemetry/opentelemetry-operator/internal/autodetect/prometheus" "github.com/open-telemetry/opentelemetry-operator/internal/autodetect/targetallocator" + apihelpers "github.com/open-telemetry/opentelemetry-operator/internal/apihelpers/v1beta1" "github.com/open-telemetry/opentelemetry-operator/internal/components" "github.com/open-telemetry/opentelemetry-operator/internal/config" "github.com/open-telemetry/opentelemetry-operator/internal/controllers" @@ -448,15 +449,15 @@ func main() { } if cfg.EnableWebhooks { - var crdMetrics *otelv1beta1.Metrics + var crdMetrics *apihelpers.Metrics if cfg.EnableCRMetrics { - meterProvider, metricsErr := otelv1beta1.BootstrapMetrics() + meterProvider, metricsErr := apihelpers.BootstrapMetrics() if metricsErr != nil { setupLog.Error(metricsErr, "Error bootstrapping CRD metrics") } - crdMetrics, err = otelv1beta1.NewMetrics(meterProvider, ctx, mgr.GetAPIReader()) + crdMetrics, err = apihelpers.NewMetrics(meterProvider, ctx, mgr.GetAPIReader()) if err != nil { setupLog.Error(err, "Error init CRD metrics") } diff --git a/pkg/collector/upgrade/v0_111_0.go b/pkg/collector/upgrade/v0_111_0.go index bd757eae3f..59d7f0dc97 100644 --- a/pkg/collector/upgrade/v0_111_0.go +++ b/pkg/collector/upgrade/v0_111_0.go @@ -10,6 +10,7 @@ import ( "github.com/go-logr/logr" "github.com/open-telemetry/opentelemetry-operator/apis/v1beta1" + apihelpers "github.com/open-telemetry/opentelemetry-operator/internal/apihelpers/v1beta1" ) func upgrade0_111_0(u VersionUpgrade, otelcol *v1beta1.OpenTelemetryCollector) (*v1beta1.OpenTelemetryCollector, error) { @@ -17,7 +18,7 @@ func upgrade0_111_0(u VersionUpgrade, otelcol *v1beta1.OpenTelemetryCollector) ( } func applyDefaults(otelcol *v1beta1.OpenTelemetryCollector, logger logr.Logger) error { - telemetryAddr, telemetryPort, err := otelcol.Spec.Config.Service.MetricsEndpoint(logger) + telemetryAddr, telemetryPort, err := apihelpers.MetricsEndpoint(&otelcol.Spec.Config.Service, logger) if err != nil { return err } diff --git a/pkg/collector/upgrade/v0_122_0.go b/pkg/collector/upgrade/v0_122_0.go index 10f96b2bc4..6b81b97537 100644 --- a/pkg/collector/upgrade/v0_122_0.go +++ b/pkg/collector/upgrade/v0_122_0.go @@ -5,16 +5,17 @@ package upgrade import ( "github.com/open-telemetry/opentelemetry-operator/apis/v1beta1" + apihelpers "github.com/open-telemetry/opentelemetry-operator/internal/apihelpers/v1beta1" ) func upgrade0_122_0(u VersionUpgrade, otelcol *v1beta1.OpenTelemetryCollector) (*v1beta1.OpenTelemetryCollector, error) { - tel := otelcol.Spec.Config.Service.GetTelemetry(u.Log) + tel := apihelpers.GetTelemetry(&otelcol.Spec.Config.Service, u.Log) if tel == nil || tel.Metrics.Address == "" { return otelcol, nil } - host, port, err := otelcol.Spec.Config.Service.MetricsEndpoint(u.Log) + host, port, err := apihelpers.MetricsEndpoint(&otelcol.Spec.Config.Service, u.Log) if err != nil { return otelcol, err } @@ -26,10 +27,10 @@ func upgrade0_122_0(u VersionUpgrade, otelcol *v1beta1.OpenTelemetryCollector) ( // differently from explicitly empty ones. By assigning "", we ensure the configuration // is updated correctly when the resource is persisted. tel.Metrics.Address = "" - reader := v1beta1.AddPrometheusMetricsEndpoint(host, port) + reader := apihelpers.AddPrometheusMetricsEndpoint(host, port) tel.Metrics.Readers = append(tel.Metrics.Readers, reader) - otelcol.Spec.Config.Service.Telemetry, err = tel.ToAnyConfig() + otelcol.Spec.Config.Service.Telemetry, err = apihelpers.ToAnyConfig(tel) if err != nil { return otelcol, err } diff --git a/pkg/sidecar/pod_test.go b/pkg/sidecar/pod_test.go index 3c25adc3fa..3e48ecec0f 100644 --- a/pkg/sidecar/pod_test.go +++ b/pkg/sidecar/pod_test.go @@ -13,6 +13,7 @@ import ( logf "sigs.k8s.io/controller-runtime/pkg/log" "github.com/open-telemetry/opentelemetry-operator/apis/v1beta1" + apihelpers "github.com/open-telemetry/opentelemetry-operator/internal/apihelpers/v1beta1" "github.com/open-telemetry/opentelemetry-operator/internal/config" "github.com/open-telemetry/opentelemetry-operator/internal/naming" ) @@ -59,7 +60,7 @@ func TestAddNativeSidecar(t *testing.T) { }, } - otelcolYaml, err := otelcol.Spec.Config.Yaml() + otelcolYaml, err := apihelpers.Yaml(&otelcol.Spec.Config) require.NoError(t, err) cfg := config.Config{ CollectorImage: "some-default-image", @@ -188,7 +189,7 @@ func TestAddSidecarWhenNoSidecarExists(t *testing.T) { }, } - otelcolYaml, err := otelcol.Spec.Config.Yaml() + otelcolYaml, err := apihelpers.Yaml(&otelcol.Spec.Config) require.NoError(t, err) cfg := config.Config{ CollectorImage: "some-default-image", From 76d1ae2ff368decb1cd6ffdbe7bc419e7e1160ce Mon Sep 17 00:00:00 2001 From: Ilia Petrov Date: Mon, 20 Apr 2026 10:41:51 +0300 Subject: [PATCH 3/3] chore: mv from internal/apihelpers -> apihelpers Signed-off-by: Ilia Petrov --- {internal/apihelpers => apihelpers}/v1beta1/config.go | 3 +-- {internal/apihelpers => apihelpers}/v1beta1/config_test.go | 2 +- {internal/apihelpers => apihelpers}/v1beta1/helpers.go | 0 {internal/apihelpers => apihelpers}/v1beta1/helpers_test.go | 0 {internal/apihelpers => apihelpers}/v1beta1/metrics.go | 0 {internal/apihelpers => apihelpers}/v1beta1/metrics_test.go | 0 .../apihelpers => apihelpers}/v1beta1/targetallocator_rbac.go | 0 internal/manifests/collector/config_replace.go | 2 +- internal/manifests/collector/configmap.go | 2 +- internal/manifests/collector/container.go | 2 +- internal/manifests/collector/ingress.go | 2 +- internal/manifests/collector/podmonitor.go | 2 +- internal/manifests/collector/rbac.go | 2 +- internal/manifests/collector/service.go | 2 +- internal/manifests/collector/servicemonitor.go | 2 +- internal/manifests/collector/volume.go | 2 +- internal/manifests/targetallocator/configmap.go | 2 +- internal/manifests/targetallocator/configmap_test.go | 2 +- internal/webhook/collector_webhook.go | 2 +- internal/webhook/collector_webhook_test.go | 2 +- internal/webhook/targetallocator_webhook.go | 2 +- main.go | 2 +- pkg/collector/upgrade/v0_111_0.go | 2 +- pkg/collector/upgrade/v0_122_0.go | 2 +- pkg/sidecar/pod_test.go | 2 +- 25 files changed, 20 insertions(+), 21 deletions(-) rename {internal/apihelpers => apihelpers}/v1beta1/config.go (99%) rename {internal/apihelpers => apihelpers}/v1beta1/config_test.go (99%) rename {internal/apihelpers => apihelpers}/v1beta1/helpers.go (100%) rename {internal/apihelpers => apihelpers}/v1beta1/helpers_test.go (100%) rename {internal/apihelpers => apihelpers}/v1beta1/metrics.go (100%) rename {internal/apihelpers => apihelpers}/v1beta1/metrics_test.go (100%) rename {internal/apihelpers => apihelpers}/v1beta1/targetallocator_rbac.go (100%) diff --git a/internal/apihelpers/v1beta1/config.go b/apihelpers/v1beta1/config.go similarity index 99% rename from internal/apihelpers/v1beta1/config.go rename to apihelpers/v1beta1/config.go index d308c5e3d7..182be47dde 100644 --- a/internal/apihelpers/v1beta1/config.go +++ b/apihelpers/v1beta1/config.go @@ -29,7 +29,7 @@ import ( type ComponentKind int const ( - KindReceiver ComponentKind = iota + KindReceiver ComponentKind = iota KindExporter KindProcessor KindExtension @@ -539,4 +539,3 @@ func AddPrometheusMetricsEndpoint(host string, port int32) otelConfig.MetricRead }, } } - diff --git a/internal/apihelpers/v1beta1/config_test.go b/apihelpers/v1beta1/config_test.go similarity index 99% rename from internal/apihelpers/v1beta1/config_test.go rename to apihelpers/v1beta1/config_test.go index 3c92c84d07..44eb9730b4 100644 --- a/internal/apihelpers/v1beta1/config_test.go +++ b/apihelpers/v1beta1/config_test.go @@ -23,7 +23,7 @@ import ( ) // testdataPath returns the path to the testdata directory, which is shared from apis/v1beta1. -const testdataPath = "../../../apis/v1beta1/testdata" +const testdataPath = "../../apis/v1beta1/testdata" func TestConfigFiles(t *testing.T) { files, err := os.ReadDir(testdataPath) diff --git a/internal/apihelpers/v1beta1/helpers.go b/apihelpers/v1beta1/helpers.go similarity index 100% rename from internal/apihelpers/v1beta1/helpers.go rename to apihelpers/v1beta1/helpers.go diff --git a/internal/apihelpers/v1beta1/helpers_test.go b/apihelpers/v1beta1/helpers_test.go similarity index 100% rename from internal/apihelpers/v1beta1/helpers_test.go rename to apihelpers/v1beta1/helpers_test.go diff --git a/internal/apihelpers/v1beta1/metrics.go b/apihelpers/v1beta1/metrics.go similarity index 100% rename from internal/apihelpers/v1beta1/metrics.go rename to apihelpers/v1beta1/metrics.go diff --git a/internal/apihelpers/v1beta1/metrics_test.go b/apihelpers/v1beta1/metrics_test.go similarity index 100% rename from internal/apihelpers/v1beta1/metrics_test.go rename to apihelpers/v1beta1/metrics_test.go diff --git a/internal/apihelpers/v1beta1/targetallocator_rbac.go b/apihelpers/v1beta1/targetallocator_rbac.go similarity index 100% rename from internal/apihelpers/v1beta1/targetallocator_rbac.go rename to apihelpers/v1beta1/targetallocator_rbac.go diff --git a/internal/manifests/collector/config_replace.go b/internal/manifests/collector/config_replace.go index ddb5e07a8e..069636eafe 100644 --- a/internal/manifests/collector/config_replace.go +++ b/internal/manifests/collector/config_replace.go @@ -6,9 +6,9 @@ package collector import ( go_yaml "github.com/goccy/go-yaml" + apihelpers "github.com/open-telemetry/opentelemetry-operator/apihelpers/v1beta1" "github.com/open-telemetry/opentelemetry-operator/apis/v1alpha1" "github.com/open-telemetry/opentelemetry-operator/apis/v1beta1" - apihelpers "github.com/open-telemetry/opentelemetry-operator/internal/apihelpers/v1beta1" "github.com/open-telemetry/opentelemetry-operator/internal/manifests/collector/adapters" ta "github.com/open-telemetry/opentelemetry-operator/internal/manifests/targetallocator/adapters" "github.com/open-telemetry/opentelemetry-operator/internal/naming" diff --git a/internal/manifests/collector/configmap.go b/internal/manifests/collector/configmap.go index 02e5f2cf3b..4d70c0d4f6 100644 --- a/internal/manifests/collector/configmap.go +++ b/internal/manifests/collector/configmap.go @@ -9,7 +9,7 @@ import ( corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - apihelpers "github.com/open-telemetry/opentelemetry-operator/internal/apihelpers/v1beta1" + apihelpers "github.com/open-telemetry/opentelemetry-operator/apihelpers/v1beta1" "github.com/open-telemetry/opentelemetry-operator/internal/autodetect/certmanager" "github.com/open-telemetry/opentelemetry-operator/internal/components" "github.com/open-telemetry/opentelemetry-operator/internal/manifests" diff --git a/internal/manifests/collector/container.go b/internal/manifests/collector/container.go index bc98400860..a95aba5fc5 100644 --- a/internal/manifests/collector/container.go +++ b/internal/manifests/collector/container.go @@ -14,10 +14,10 @@ import ( corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/util/validation" + apihelpers "github.com/open-telemetry/opentelemetry-operator/apihelpers/v1beta1" "github.com/open-telemetry/opentelemetry-operator/apis/v1beta1" "github.com/open-telemetry/opentelemetry-operator/internal/autodetect/certmanager" "github.com/open-telemetry/opentelemetry-operator/internal/config" - apihelpers "github.com/open-telemetry/opentelemetry-operator/internal/apihelpers/v1beta1" "github.com/open-telemetry/opentelemetry-operator/internal/naming" "github.com/open-telemetry/opentelemetry-operator/pkg/constants" "github.com/open-telemetry/opentelemetry-operator/pkg/featuregate" diff --git a/internal/manifests/collector/ingress.go b/internal/manifests/collector/ingress.go index fac74748a6..e2ba220f6a 100644 --- a/internal/manifests/collector/ingress.go +++ b/internal/manifests/collector/ingress.go @@ -11,8 +11,8 @@ import ( networkingv1 "k8s.io/api/networking/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + apihelpers "github.com/open-telemetry/opentelemetry-operator/apihelpers/v1beta1" "github.com/open-telemetry/opentelemetry-operator/apis/v1beta1" - apihelpers "github.com/open-telemetry/opentelemetry-operator/internal/apihelpers/v1beta1" "github.com/open-telemetry/opentelemetry-operator/internal/manifests" "github.com/open-telemetry/opentelemetry-operator/internal/manifests/manifestutils" "github.com/open-telemetry/opentelemetry-operator/internal/naming" diff --git a/internal/manifests/collector/podmonitor.go b/internal/manifests/collector/podmonitor.go index 08e4155443..46d92f8abd 100644 --- a/internal/manifests/collector/podmonitor.go +++ b/internal/manifests/collector/podmonitor.go @@ -10,9 +10,9 @@ import ( monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + apihelpers "github.com/open-telemetry/opentelemetry-operator/apihelpers/v1beta1" "github.com/open-telemetry/opentelemetry-operator/apis/v1beta1" "github.com/open-telemetry/opentelemetry-operator/internal/autodetect/prometheus" - apihelpers "github.com/open-telemetry/opentelemetry-operator/internal/apihelpers/v1beta1" "github.com/open-telemetry/opentelemetry-operator/internal/manifests" "github.com/open-telemetry/opentelemetry-operator/internal/manifests/manifestutils" "github.com/open-telemetry/opentelemetry-operator/internal/naming" diff --git a/internal/manifests/collector/rbac.go b/internal/manifests/collector/rbac.go index 505f87f3c7..8ef3b9202f 100644 --- a/internal/manifests/collector/rbac.go +++ b/internal/manifests/collector/rbac.go @@ -10,7 +10,7 @@ import ( rbacv1 "k8s.io/api/rbac/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - apihelpers "github.com/open-telemetry/opentelemetry-operator/internal/apihelpers/v1beta1" + apihelpers "github.com/open-telemetry/opentelemetry-operator/apihelpers/v1beta1" "github.com/open-telemetry/opentelemetry-operator/internal/manifests" "github.com/open-telemetry/opentelemetry-operator/internal/manifests/manifestutils" "github.com/open-telemetry/opentelemetry-operator/internal/naming" diff --git a/internal/manifests/collector/service.go b/internal/manifests/collector/service.go index df4131c86d..3bb513e314 100644 --- a/internal/manifests/collector/service.go +++ b/internal/manifests/collector/service.go @@ -12,8 +12,8 @@ import ( corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + apihelpers "github.com/open-telemetry/opentelemetry-operator/apihelpers/v1beta1" "github.com/open-telemetry/opentelemetry-operator/apis/v1beta1" - apihelpers "github.com/open-telemetry/opentelemetry-operator/internal/apihelpers/v1beta1" "github.com/open-telemetry/opentelemetry-operator/internal/manifests" "github.com/open-telemetry/opentelemetry-operator/internal/manifests/manifestutils" "github.com/open-telemetry/opentelemetry-operator/internal/naming" diff --git a/internal/manifests/collector/servicemonitor.go b/internal/manifests/collector/servicemonitor.go index 79b1d85399..8186b3b84b 100644 --- a/internal/manifests/collector/servicemonitor.go +++ b/internal/manifests/collector/servicemonitor.go @@ -11,9 +11,9 @@ import ( monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + apihelpers "github.com/open-telemetry/opentelemetry-operator/apihelpers/v1beta1" "github.com/open-telemetry/opentelemetry-operator/apis/v1beta1" "github.com/open-telemetry/opentelemetry-operator/internal/autodetect/prometheus" - apihelpers "github.com/open-telemetry/opentelemetry-operator/internal/apihelpers/v1beta1" "github.com/open-telemetry/opentelemetry-operator/internal/manifests" "github.com/open-telemetry/opentelemetry-operator/internal/manifests/manifestutils" "github.com/open-telemetry/opentelemetry-operator/internal/naming" diff --git a/internal/manifests/collector/volume.go b/internal/manifests/collector/volume.go index 0ac6cc30a4..713e1e221f 100644 --- a/internal/manifests/collector/volume.go +++ b/internal/manifests/collector/volume.go @@ -8,8 +8,8 @@ import ( "github.com/go-logr/logr" corev1 "k8s.io/api/core/v1" + apihelpers "github.com/open-telemetry/opentelemetry-operator/apihelpers/v1beta1" "github.com/open-telemetry/opentelemetry-operator/apis/v1beta1" - apihelpers "github.com/open-telemetry/opentelemetry-operator/internal/apihelpers/v1beta1" "github.com/open-telemetry/opentelemetry-operator/internal/autodetect/certmanager" "github.com/open-telemetry/opentelemetry-operator/internal/components" "github.com/open-telemetry/opentelemetry-operator/internal/config" diff --git a/internal/manifests/targetallocator/configmap.go b/internal/manifests/targetallocator/configmap.go index 2b9c578a33..728fcbe7d1 100644 --- a/internal/manifests/targetallocator/configmap.go +++ b/internal/manifests/targetallocator/configmap.go @@ -11,8 +11,8 @@ import ( corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + apihelpers "github.com/open-telemetry/opentelemetry-operator/apihelpers/v1beta1" "github.com/open-telemetry/opentelemetry-operator/apis/v1beta1" - apihelpers "github.com/open-telemetry/opentelemetry-operator/internal/apihelpers/v1beta1" "github.com/open-telemetry/opentelemetry-operator/internal/autodetect/certmanager" "github.com/open-telemetry/opentelemetry-operator/internal/manifests/collector" "github.com/open-telemetry/opentelemetry-operator/internal/manifests/manifestutils" diff --git a/internal/manifests/targetallocator/configmap_test.go b/internal/manifests/targetallocator/configmap_test.go index c693f45664..dd302fb9c8 100644 --- a/internal/manifests/targetallocator/configmap_test.go +++ b/internal/manifests/targetallocator/configmap_test.go @@ -15,8 +15,8 @@ import ( colfg "go.opentelemetry.io/collector/featuregate" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + apihelpers "github.com/open-telemetry/opentelemetry-operator/apihelpers/v1beta1" "github.com/open-telemetry/opentelemetry-operator/apis/v1beta1" - apihelpers "github.com/open-telemetry/opentelemetry-operator/internal/apihelpers/v1beta1" "github.com/open-telemetry/opentelemetry-operator/internal/autodetect/certmanager" "github.com/open-telemetry/opentelemetry-operator/internal/config" "github.com/open-telemetry/opentelemetry-operator/pkg/featuregate" diff --git a/internal/webhook/collector_webhook.go b/internal/webhook/collector_webhook.go index 2371c95004..b9be924748 100644 --- a/internal/webhook/collector_webhook.go +++ b/internal/webhook/collector_webhook.go @@ -17,13 +17,13 @@ import ( ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/webhook/admission" + apihelpers "github.com/open-telemetry/opentelemetry-operator/apihelpers/v1beta1" "github.com/open-telemetry/opentelemetry-operator/apis/v1beta1" "github.com/open-telemetry/opentelemetry-operator/internal/config" "github.com/open-telemetry/opentelemetry-operator/internal/fips" ta "github.com/open-telemetry/opentelemetry-operator/internal/manifests/targetallocator/adapters" "github.com/open-telemetry/opentelemetry-operator/internal/naming" "github.com/open-telemetry/opentelemetry-operator/internal/rbac" - apihelpers "github.com/open-telemetry/opentelemetry-operator/internal/apihelpers/v1beta1" "github.com/open-telemetry/opentelemetry-operator/pkg/featuregate" ) diff --git a/internal/webhook/collector_webhook_test.go b/internal/webhook/collector_webhook_test.go index 317bf9679c..918632407c 100644 --- a/internal/webhook/collector_webhook_test.go +++ b/internal/webhook/collector_webhook_test.go @@ -30,8 +30,8 @@ import ( "k8s.io/utils/ptr" "sigs.k8s.io/controller-runtime/pkg/webhook/admission" + apihelpers "github.com/open-telemetry/opentelemetry-operator/apihelpers/v1beta1" "github.com/open-telemetry/opentelemetry-operator/apis/v1beta1" - apihelpers "github.com/open-telemetry/opentelemetry-operator/internal/apihelpers/v1beta1" "github.com/open-telemetry/opentelemetry-operator/internal/config" "github.com/open-telemetry/opentelemetry-operator/internal/manifests" collectorManifests "github.com/open-telemetry/opentelemetry-operator/internal/manifests/collector" diff --git a/internal/webhook/targetallocator_webhook.go b/internal/webhook/targetallocator_webhook.go index 510c55b3b2..d28f789a8b 100644 --- a/internal/webhook/targetallocator_webhook.go +++ b/internal/webhook/targetallocator_webhook.go @@ -13,9 +13,9 @@ import ( ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/webhook/admission" + apihelpers "github.com/open-telemetry/opentelemetry-operator/apihelpers/v1beta1" "github.com/open-telemetry/opentelemetry-operator/apis/v1alpha1" "github.com/open-telemetry/opentelemetry-operator/apis/v1beta1" - apihelpers "github.com/open-telemetry/opentelemetry-operator/internal/apihelpers/v1beta1" "github.com/open-telemetry/opentelemetry-operator/internal/config" "github.com/open-telemetry/opentelemetry-operator/internal/naming" "github.com/open-telemetry/opentelemetry-operator/internal/rbac" diff --git a/main.go b/main.go index 2899a9c80c..52be1b1079 100644 --- a/main.go +++ b/main.go @@ -44,6 +44,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/webhook/admission" gatewayv1 "sigs.k8s.io/gateway-api/apis/v1" + apihelpers "github.com/open-telemetry/opentelemetry-operator/apihelpers/v1beta1" otelv1alpha1 "github.com/open-telemetry/opentelemetry-operator/apis/v1alpha1" otelv1beta1 "github.com/open-telemetry/opentelemetry-operator/apis/v1beta1" "github.com/open-telemetry/opentelemetry-operator/internal/autodetect" @@ -53,7 +54,6 @@ import ( "github.com/open-telemetry/opentelemetry-operator/internal/autodetect/openshift" "github.com/open-telemetry/opentelemetry-operator/internal/autodetect/prometheus" "github.com/open-telemetry/opentelemetry-operator/internal/autodetect/targetallocator" - apihelpers "github.com/open-telemetry/opentelemetry-operator/internal/apihelpers/v1beta1" "github.com/open-telemetry/opentelemetry-operator/internal/components" "github.com/open-telemetry/opentelemetry-operator/internal/config" "github.com/open-telemetry/opentelemetry-operator/internal/controllers" diff --git a/pkg/collector/upgrade/v0_111_0.go b/pkg/collector/upgrade/v0_111_0.go index 59d7f0dc97..26743600ba 100644 --- a/pkg/collector/upgrade/v0_111_0.go +++ b/pkg/collector/upgrade/v0_111_0.go @@ -9,8 +9,8 @@ import ( "dario.cat/mergo" "github.com/go-logr/logr" + apihelpers "github.com/open-telemetry/opentelemetry-operator/apihelpers/v1beta1" "github.com/open-telemetry/opentelemetry-operator/apis/v1beta1" - apihelpers "github.com/open-telemetry/opentelemetry-operator/internal/apihelpers/v1beta1" ) func upgrade0_111_0(u VersionUpgrade, otelcol *v1beta1.OpenTelemetryCollector) (*v1beta1.OpenTelemetryCollector, error) { diff --git a/pkg/collector/upgrade/v0_122_0.go b/pkg/collector/upgrade/v0_122_0.go index 6b81b97537..850867d71f 100644 --- a/pkg/collector/upgrade/v0_122_0.go +++ b/pkg/collector/upgrade/v0_122_0.go @@ -4,8 +4,8 @@ package upgrade import ( + apihelpers "github.com/open-telemetry/opentelemetry-operator/apihelpers/v1beta1" "github.com/open-telemetry/opentelemetry-operator/apis/v1beta1" - apihelpers "github.com/open-telemetry/opentelemetry-operator/internal/apihelpers/v1beta1" ) func upgrade0_122_0(u VersionUpgrade, otelcol *v1beta1.OpenTelemetryCollector) (*v1beta1.OpenTelemetryCollector, error) { diff --git a/pkg/sidecar/pod_test.go b/pkg/sidecar/pod_test.go index 3e48ecec0f..42e7a2561e 100644 --- a/pkg/sidecar/pod_test.go +++ b/pkg/sidecar/pod_test.go @@ -12,8 +12,8 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" logf "sigs.k8s.io/controller-runtime/pkg/log" + apihelpers "github.com/open-telemetry/opentelemetry-operator/apihelpers/v1beta1" "github.com/open-telemetry/opentelemetry-operator/apis/v1beta1" - apihelpers "github.com/open-telemetry/opentelemetry-operator/internal/apihelpers/v1beta1" "github.com/open-telemetry/opentelemetry-operator/internal/config" "github.com/open-telemetry/opentelemetry-operator/internal/naming" )