Skip to content

feat: add OtelExporterEndpoint crd#449

Open
sofiasimdianova wants to merge 3 commits into
mainfrom
feat/otelexportercrd-support
Open

feat: add OtelExporterEndpoint crd#449
sofiasimdianova wants to merge 3 commits into
mainfrom
feat/otelexportercrd-support

Conversation

@sofiasimdianova
Copy link
Copy Markdown

No description provided.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 6, 2026

Review Change Stack

Warning

Review limit reached

@sofiasimdianova, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 38 minutes and 32 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8355580d-ce70-47ac-817d-e2ced1e08e0c

📥 Commits

Reviewing files that changed from the base of the PR and between aa00b58 and b369969.

⛔ Files ignored due to path filters (3)
  • config/crd/bases/formance.com_otelexporterendpoints.yaml is excluded by !**/*.yaml
  • docs/09-Configuration reference/settings.catalog.json is excluded by !**/*.json
  • helm/crds/templates/crds/apiextensions.k8s.io_v1_customresourcedefinition_otelexporterendpoints.formance.com.yaml is excluded by !**/*.yaml
📒 Files selected for processing (9)
  • api/formance.com/v1beta1/otelexporterendpoint_types.go
  • cmd/main.go
  • docs/09-Configuration reference/02-Custom Resource Definitions.md
  • internal/core/platform.go
  • internal/resources/otelexporterendpoints/collector_config.go
  • internal/resources/otelexporterendpoints/collector_config_test.go
  • internal/resources/otelexporterendpoints/init.go
  • internal/resources/settings/opentelemetry.go
  • internal/tests/otelexporterendpoint_controller_test.go

Walkthrough

Adds an OtelExporterEndpoint CRD, generator for merged OpenTelemetry Collector configs, a controller reconciling per-stack Collector Deployment/Service/ConfigMap, settings integration for in-cluster collectors, CLI/platform wiring, unit and controller tests, and documentation.

Changes

OtelExporterEndpoint CRD and Controller Implementation

Layer / File(s) Summary
API contract and CRD definition
api/formance.com/v1beta1/otelexporterendpoint_types.go, api/formance.com/v1beta1/zz_generated.deepcopy.go, docs/09-Configuration reference/02-Custom Resource Definitions.md
Defines the OtelExporterEndpoint CRD types (spec/status/auth/signal/resourceAttributes), kubebuilder annotations, readiness helpers, list type/registration, and generated deepcopy implementations; documents the CRD.
Collector configuration generation
internal/resources/otelexporterendpoints/collector_config.go
Generates merged OpenTelemetry Collector YAML from endpoints and optional global settings: protocol inference, exporter building (auth/env alias), resource-attributes processors, deterministic pipeline grouping, and YAML marshaling.
Configuration generation tests
internal/resources/otelexporterendpoints/collector_config_test.go
Unit tests for merged-config generation and helpers: protocol inference, insecure gRPC handling, scheme stripping, name/env sanitization, auth env aliasing, and build inputs.
Controller reconciliation and resource management
internal/resources/otelexporterendpoints/init.go
Reconciles matching stacks, finds matching endpoints, builds collector inputs, generates/stores ConfigMap, computes config/secret hashes, creates/updates Deployment and Service, computes readiness, patches Stack annotations, and performs cleanup via finalizer and resource reference reconciliation.
Settings / OTEL env integration
internal/resources/settings/opentelemetry.go
Discovers in-namespace otel-collector Service and emits OTEL env vars targeting it (resource attributes, POD_NAME fieldRef); preserves DSN fallback; switches to corev1.EnvVar types.
Collector image configuration & package init
cmd/main.go, internal/core/platform.go, internal/resources/all.go
Adds --collector-image CLI flag, Platform.CollectorImage and DefaultCollectorImage constant, and blank import of otelexporterendpoints package.
Controller integration tests
internal/tests/otelexporterendpoint_controller_test.go
Ginkgo/Gomega integration tests validating endpoint-stack matching, collector resources creation/removal, auth secret wiring, and settings fallback behavior.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Suggested reviewers

  • gfyrag

Poem

🐰 I hopped through YAML and code today,

Built collectors per stack where endpoints play,
Env vars sorted, secrets hashed with care,
Pipelines wired so traces and metrics share,
A tiny rabbit cheers observability everywhere!

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive No pull request description was provided by the author. While a description would be helpful for context, the absence itself does not constitute failure—this is a very lenient check that only fails when description is completely off-topic or unrelated. Consider adding a pull request description that explains the purpose, usage, and integration details of the new OtelExporterEndpoint CRD to help reviewers understand the change.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: add OtelExporterEndpoint crd' is specific, clear, and directly describes the main addition: a new OtelExporterEndpoint Custom Resource Definition. It accurately captures the primary change across the changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/otelexportercrd-support

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@sofiasimdianova sofiasimdianova changed the title rip: add OtelExporterEndpoint crd wip: add OtelExporterEndpoint crd May 6, 2026
Comment thread api/formance.com/v1beta1/otelexporterendpoint_types.go Outdated
Comment thread api/formance.com/v1beta1/otelexporterendpoint_types.go Outdated
Comment thread api/formance.com/v1beta1/otelexporterendpoint_types.go Outdated
Comment thread cmd/main.go Outdated
Comment thread config/samples/formance.com_v1beta1_otelexporterendpoint.yaml Outdated
Comment thread config/samples/formance.com_v1beta1_otelexporterendpoint.yaml Outdated
@Dav-14
Copy link
Copy Markdown
Contributor

Dav-14 commented May 7, 2026

Dirty is not passing. Make sure to run just pc

@sofiasimdianova sofiasimdianova force-pushed the feat/otelexportercrd-support branch 2 times, most recently from b9260f3 to 3bfc797 Compare May 12, 2026 14:31
Comment thread helm/operator/templates/otelexporterendpoint-support.yaml Outdated
Comment thread helm/operator/values.yaml Outdated
Comment thread helm/operator/values.yaml Outdated
@sofiasimdianova sofiasimdianova force-pushed the feat/otelexportercrd-support branch 2 times, most recently from cb99db5 to b37ed89 Compare May 20, 2026 11:41
@sofiasimdianova sofiasimdianova force-pushed the feat/otelexportercrd-support branch from b37ed89 to de76074 Compare June 1, 2026 15:05
@sofiasimdianova sofiasimdianova changed the title wip: add OtelExporterEndpoint crd feat: add OtelExporterEndpoint crd Jun 1, 2026
@sofiasimdianova sofiasimdianova force-pushed the feat/otelexportercrd-support branch from de76074 to 6e38209 Compare June 2, 2026 12:54
@sofiasimdianova sofiasimdianova force-pushed the feat/otelexportercrd-support branch from 6e38209 to c925b4f Compare June 2, 2026 13:01
@sofiasimdianova sofiasimdianova marked this pull request as ready for review June 2, 2026 15:13
@sofiasimdianova sofiasimdianova requested a review from a team as a code owner June 2, 2026 15:13
@sofiasimdianova sofiasimdianova requested a review from Dav-14 June 2, 2026 15:13
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (4)
docs/09-Configuration reference/02-Custom Resource Definitions.md (1)

2267-2267: ⚡ Quick win

Document what status.stacks contains.

stacks currently has an empty description. Please describe that it lists the matched stack names for this endpoint (sorted), so operators can interpret status without reading controller code.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/09-Configuration` reference/02-Custom Resource Definitions.md at line
2267, The docs entry for status.stacks is missing a description; update the
table row for `stacks` (status.stacks) to explain that it lists the matched
stack names for this endpoint and that the list is returned in a stable sorted
order so operators can interpret status without inspecting controller code
(e.g., "Lists the matched stack names for this endpoint, returned as a sorted
array of strings").
api/formance.com/v1beta1/otelexporterendpoint_types.go (2)

29-34: ⚡ Quick win

Consider adding URL format validation for the Endpoint field.

The Endpoint field accepts any string without validation. Invalid URLs would only be caught during collector configuration generation or at runtime, reducing early feedback.

🛡️ Suggested validation
 type OtelSignalConfig struct {
+	// +kubebuilder:validation:Pattern=`^(https?|grpc)://.*$`
 	Endpoint string `json:"endpoint"`
 
 	// +optional
 	Auth *OtelAuthConfig `json:"auth,omitempty"`
 }

Note: The pattern can be adjusted based on accepted endpoint formats. The collector config generator currently handles http://, https://, grpc://, and bare hostnames.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@api/formance.com/v1beta1/otelexporterendpoint_types.go` around lines 29 - 34,
Add URL/hostname validation for the OtelSignalConfig.Endpoint field so invalid
endpoints are caught at CRD validation time: update the OtelSignalConfig struct
(type OtelSignalConfig) and add a kubebuilder validation marker above the
Endpoint field (for example a +kubebuilder:validation:Pattern comment or
+kubebuilder:validation:Format) that matches allowed schemes (http://, https://,
grpc://) and bare hostnames; ensure the json tag remains `json:"endpoint"` and
keep the Auth field unchanged.

23-27: ⚡ Quick win

Consider adding validation for the FromSecret field.

The FromSecret field references a Kubernetes secret name but has no validation markers. When Type is "bearer", an empty FromSecret would cause runtime failures during auth token lookup.

🛡️ Suggested validation
 type OtelAuthConfig struct {
 	// +kubebuilder:validation:Enum=bearer
 	Type       string `json:"type"`
+	// +kubebuilder:validation:MinLength=1
 	FromSecret string `json:"fromSecret"`
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@api/formance.com/v1beta1/otelexporterendpoint_types.go` around lines 23 - 27,
Add validation markers to OtelAuthConfig.FromSecret so secret names cannot be
empty and must match Kubernetes DNS-1123 naming; for example add kubebuilder
markers like +kubebuilder:validation:MinLength=1 and
+kubebuilder:validation:Pattern="^[a-z0-9]([-a-z0-9]*[a-z0-9])?$" (and
optionally +kubebuilder:validation:MaxLength=253) on the FromSecret field; if
you need strict enforcement only when OtelAuthConfig.Type == "bearer", implement
a validating webhook (referencing the OtelAuthConfig.Type and FromSecret fields)
to reject objects where Type is "bearer" and FromSecret is empty/invalid.
internal/resources/otelexporterendpoints/collector_config.go (1)

202-215: ⚡ Quick win

Refactor redundant nop exporter additions.

The "nop" exporter is added to the exporters map up to three times (lines 203, 209, 213). While map overwrites are safe, this is redundant and reduces clarity.

♻️ Proposed refactoring
+	needsNop := len(tracesPipelines) == 0 || len(metricsPipelines) == 0
+	if needsNop {
+		exporters["nop"] = struct{}{}
+	}
+
-	if len(tracesPipelines) == 0 && len(metricsPipelines) == 0 {
-		exporters["nop"] = struct{}{}
+	if len(tracesPipelines) == 0 {
 		tracesPipelines = []pipelineContribution{{exporter: "nop"}}
-		metricsPipelines = []pipelineContribution{{exporter: "nop"}}
 	}
 
-	if len(tracesPipelines) == 0 {
-		exporters["nop"] = struct{}{}
-		tracesPipelines = []pipelineContribution{{exporter: "nop"}}
-	}
-	if len(metricsPipelines) == 0 {
-		exporters["nop"] = struct{}{}
+	if len(metricsPipelines) == 0 {
 		metricsPipelines = []pipelineContribution{{exporter: "nop"}}
 	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/resources/otelexporterendpoints/collector_config.go` around lines
202 - 215, The code redundantly inserts the "nop" key into the exporters map
multiple times; consolidate this by checking whether either tracesPipelines or
metricsPipelines is empty and adding exporters["nop"] = struct{}{} only once
before assigning default pipelineContribution values to tracesPipelines and/or
metricsPipelines; update the block handling tracesPipelines, metricsPipelines
and exporters (refer to symbols tracesPipelines, metricsPipelines, exporters and
type pipelineContribution) so that the "nop" exporter is added a single time
when any default pipeline is needed.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/09-Configuration` reference/02-Custom Resource Definitions.md:
- Around line 2235-2236: The document has broken anchor links for
OtelSignalConfig referenced from the `traces` and `metrics` table entries; add a
corresponding heading "##### OtelSignalConfig" (or rename an existing matching
section) so the fragment `#otelsignalconfig` exists, and ensure the heading text
exactly matches the anchor target used by the table (case/spacing) so the links
from `traces` and `metrics` resolve correctly; update either the table links or
the heading name to match each other.

---

Nitpick comments:
In `@api/formance.com/v1beta1/otelexporterendpoint_types.go`:
- Around line 29-34: Add URL/hostname validation for the
OtelSignalConfig.Endpoint field so invalid endpoints are caught at CRD
validation time: update the OtelSignalConfig struct (type OtelSignalConfig) and
add a kubebuilder validation marker above the Endpoint field (for example a
+kubebuilder:validation:Pattern comment or +kubebuilder:validation:Format) that
matches allowed schemes (http://, https://, grpc://) and bare hostnames; ensure
the json tag remains `json:"endpoint"` and keep the Auth field unchanged.
- Around line 23-27: Add validation markers to OtelAuthConfig.FromSecret so
secret names cannot be empty and must match Kubernetes DNS-1123 naming; for
example add kubebuilder markers like +kubebuilder:validation:MinLength=1 and
+kubebuilder:validation:Pattern="^[a-z0-9]([-a-z0-9]*[a-z0-9])?$" (and
optionally +kubebuilder:validation:MaxLength=253) on the FromSecret field; if
you need strict enforcement only when OtelAuthConfig.Type == "bearer", implement
a validating webhook (referencing the OtelAuthConfig.Type and FromSecret fields)
to reject objects where Type is "bearer" and FromSecret is empty/invalid.

In `@docs/09-Configuration` reference/02-Custom Resource Definitions.md:
- Line 2267: The docs entry for status.stacks is missing a description; update
the table row for `stacks` (status.stacks) to explain that it lists the matched
stack names for this endpoint and that the list is returned in a stable sorted
order so operators can interpret status without inspecting controller code
(e.g., "Lists the matched stack names for this endpoint, returned as a sorted
array of strings").

In `@internal/resources/otelexporterendpoints/collector_config.go`:
- Around line 202-215: The code redundantly inserts the "nop" key into the
exporters map multiple times; consolidate this by checking whether either
tracesPipelines or metricsPipelines is empty and adding exporters["nop"] =
struct{}{} only once before assigning default pipelineContribution values to
tracesPipelines and/or metricsPipelines; update the block handling
tracesPipelines, metricsPipelines and exporters (refer to symbols
tracesPipelines, metricsPipelines, exporters and type pipelineContribution) so
that the "nop" exporter is added a single time when any default pipeline is
needed.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b6d84291-4282-4091-82a2-6514531e199c

📥 Commits

Reviewing files that changed from the base of the PR and between b101556 and 896f3da.

⛔ Files ignored due to path filters (10)
  • config/crd/bases/formance.com_otelexporterendpoints.yaml is excluded by !**/*.yaml
  • config/crd/kustomization.yaml is excluded by !**/*.yaml
  • config/rbac/role.yaml is excluded by !**/*.yaml
  • config/samples/formance.com_v1beta1_otelexporterendpoint.yaml is excluded by !**/*.yaml
  • docs/09-Configuration reference/settings.catalog.json is excluded by !**/*.json
  • helm/crds/templates/crds/apiextensions.k8s.io_v1_customresourcedefinition_otelexporterendpoints.formance.com.yaml is excluded by !**/*.yaml
  • helm/operator/templates/deployment.yaml is excluded by !**/*.yaml
  • helm/operator/templates/gen/rbac.authorization.k8s.io_v1_clusterrole_formance-manager-role.yaml is excluded by !**/gen/**, !**/*.yaml, !**/gen/**
  • helm/operator/templates/otelexporterendpoint-support.yaml is excluded by !**/*.yaml
  • helm/operator/values.yaml is excluded by !**/*.yaml
📒 Files selected for processing (11)
  • api/formance.com/v1beta1/otelexporterendpoint_types.go
  • api/formance.com/v1beta1/zz_generated.deepcopy.go
  • cmd/main.go
  • docs/09-Configuration reference/02-Custom Resource Definitions.md
  • internal/core/platform.go
  • internal/resources/all.go
  • internal/resources/otelexporterendpoints/collector_config.go
  • internal/resources/otelexporterendpoints/collector_config_test.go
  • internal/resources/otelexporterendpoints/init.go
  • internal/resources/settings/opentelemetry.go
  • internal/tests/otelexporterendpoint_controller_test.go

Comment thread docs/09-Configuration reference/02-Custom Resource Definitions.md Outdated
Copy link
Copy Markdown
Member

@flemzord flemzord left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inline review comments focused on production-readiness risks, ownership/cleanup semantics, cross-controller reconciliation, validation gaps, and failure modes.

Comment thread internal/resources/otelexporterendpoints/init.go
Comment thread internal/resources/otelexporterendpoints/init.go
Comment thread internal/resources/otelexporterendpoints/init.go Outdated
Comment thread internal/resources/otelexporterendpoints/init.go
Comment thread internal/resources/otelexporterendpoints/init.go Outdated
Comment thread internal/resources/otelexporterendpoints/init.go
Comment thread internal/resources/otelexporterendpoints/collector_config.go Outdated
Comment thread internal/resources/settings/opentelemetry.go Outdated
Comment thread internal/resources/settings/opentelemetry.go Outdated
Comment thread api/formance.com/v1beta1/otelexporterendpoint_types.go
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/core/platform.go`:
- Line 4: The DefaultCollectorImage value is pinned to an older OpenTelemetry
Collector image; update the constant DefaultCollectorImage to use the latest
stable tag (e.g., change "otel/opentelemetry-collector-contrib:0.151.0" to
"otel/opentelemetry-collector-contrib:0.153.0" or a newer stable release), run
an image vulnerability scan on the new image and commit any resulting fixes, and
update any related documentation or deployment manifests that reference
DefaultCollectorImage to match the new tag.

In `@internal/resources/otelexporterendpoints/init.go`:
- Around line 108-116: The loop drops orphaned stacks from
endpoint.Status.Stacks even when cleanupStackCollector(ctx, prev) fails;
instead, build a new list preserving any prev that either is still targeted
(targetedStacks[prev]) or whose cleanup failed, and only remove prev from the
status when cleanupStackCollector succeeds; update endpoint.Status.Stacks to
that new list (use the existing variables cleanupStackCollector, targetedStacks,
stackNames, and endpoint.Status.Stacks) so failed cleanups remain in the status
for retry while successful cleanups are removed.

In `@internal/resources/settings/opentelemetry.go`:
- Around line 56-72: The getCollectorInfo function currently trusts any Service
named by collectorServiceName; modify it to ignore Services not managed by our
controller by checking the same management annotation used in
otelexporterendpoints (e.g., look for svc.Annotations["formance.com/managed-by"]
== "otelexporterendpoint") and treat Services without that annotation (or with a
different value) as not found (return nil, nil) so they don't affect DSN
fallback or telemetry; update getCollectorInfo to perform this annotation check
before setting hasTraces/hasMetrics and constructing the endpoint.

In `@internal/tests/otelexporterendpoint_controller_test.go`:
- Around line 121-144: The test currently only waits for the Deployment to exist
before deleting the endpoint, so the subsequent ShouldNot(Succeed()) checks for
Service and ConfigMap can pass if those resources were never created; update the
It block to assert the Service ("otel-collector") and ConfigMap
("otel-collector-config") exist before the delete step by adding Eventually(...)
assertions that call LoadResource(stack.Name, "otel-collector",
&corev1.Service{}) and LoadResource(stack.Name, "otel-collector-config",
&corev1.ConfigMap{}) and assert Should(Succeed()) (similar to the existing
Deployment check) so cleanup verification is meaningful.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 29ac74d2-9563-4812-b64a-455492e5a406

📥 Commits

Reviewing files that changed from the base of the PR and between 896f3da and 5e95dda.

⛔ Files ignored due to path filters (3)
  • config/crd/bases/formance.com_otelexporterendpoints.yaml is excluded by !**/*.yaml
  • docs/09-Configuration reference/settings.catalog.json is excluded by !**/*.json
  • helm/crds/templates/crds/apiextensions.k8s.io_v1_customresourcedefinition_otelexporterendpoints.formance.com.yaml is excluded by !**/*.yaml
📒 Files selected for processing (8)
  • api/formance.com/v1beta1/otelexporterendpoint_types.go
  • cmd/main.go
  • internal/core/platform.go
  • internal/resources/otelexporterendpoints/collector_config.go
  • internal/resources/otelexporterendpoints/collector_config_test.go
  • internal/resources/otelexporterendpoints/init.go
  • internal/resources/settings/opentelemetry.go
  • internal/tests/otelexporterendpoint_controller_test.go
🚧 Files skipped from review as they are similar to previous changes (3)
  • api/formance.com/v1beta1/otelexporterendpoint_types.go
  • cmd/main.go
  • internal/resources/otelexporterendpoints/collector_config.go

Comment thread internal/core/platform.go
Comment thread internal/resources/otelexporterendpoints/init.go Outdated
Comment thread internal/resources/settings/opentelemetry.go
Comment thread internal/tests/otelexporterendpoint_controller_test.go
@sofiasimdianova sofiasimdianova force-pushed the feat/otelexportercrd-support branch from 5e95dda to bb59f12 Compare June 3, 2026 15:46
@sofiasimdianova sofiasimdianova requested a review from flemzord June 3, 2026 16:02
Copy link
Copy Markdown
Member

@flemzord flemzord left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Second deep review pass after the latest updates. I focused on production readiness and remaining behavioral risks.

Comment thread internal/resources/otelexporterendpoints/init.go
Comment thread helm/operator/templates/otelexporterendpoint-support.yaml
Comment thread internal/resources/otelexporterendpoints/init.go Outdated
Comment thread internal/resources/settings/opentelemetry.go
Comment thread internal/resources/otelexporterendpoints/init.go
Comment thread internal/resources/otelexporterendpoints/init.go Outdated
Comment thread docs/09-Configuration reference/02-Custom Resource Definitions.md Outdated
@sofiasimdianova sofiasimdianova force-pushed the feat/otelexportercrd-support branch from bb59f12 to aa00b58 Compare June 4, 2026 16:06
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
docs/09-Configuration reference/02-Custom Resource Definitions.md (1)

2235-2236: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix broken OtelSignalConfig anchor links.

Both links target #otelsignalconfig, but that anchor is not defined in the document, so navigation and markdownlint MD051 fail. Add a ##### OtelSignalConfig section (or point these links to an existing valid anchor).

Suggested minimal doc fix
+##### OtelSignalConfig
+
+OtelSignalConfig configures a single signal type (traces or metrics).
+
+| Field | Description | Default | Validation |
+| --- | --- | --- | --- |
+| `endpoint` _string_ | Endpoint URL for the signal. Protocol is inferred from scheme (`grpc://`, `http://`, `https://`). |  |  |
+| `auth` _[OtelAuthConfig](`#otelauthconfig`)_ | Optional per-signal authentication configuration. |  |  |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/09-Configuration` reference/02-Custom Resource Definitions.md around
lines 2235 - 2236, The markdown links for `OtelSignalConfig` used in the
`traces` and `metrics` table rows point to a non-existent `#otelsignalconfig`
anchor; add a matching heading (e.g., insert a "##### OtelSignalConfig" section
with the OtelSignalConfig definition) or update the two links to an existing
valid anchor so the `traces` and `metrics` table entries resolve correctly and
satisfy markdownlint MD051.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/tests/otelexporterendpoint_controller_test.go`:
- Around line 118-120: AfterEach currently only deletes the stack
(Delete(stack)), which can leave the endpoint resource leaking if a test fails
before it's created; update the AfterEach to unconditionally attempt cleanup of
the endpoint as well (call Delete(endpoint) or an unconditional cleanup helper)
in addition to Delete(stack), and ensure the cleanup ignores not-found errors so
it always runs without causing further test failures; locate the AfterEach block
and add the unconditional endpoint cleanup referencing the endpoint variable and
the existing Delete(stack) call.

---

Duplicate comments:
In `@docs/09-Configuration` reference/02-Custom Resource Definitions.md:
- Around line 2235-2236: The markdown links for `OtelSignalConfig` used in the
`traces` and `metrics` table rows point to a non-existent `#otelsignalconfig`
anchor; add a matching heading (e.g., insert a "##### OtelSignalConfig" section
with the OtelSignalConfig definition) or update the two links to an existing
valid anchor so the `traces` and `metrics` table entries resolve correctly and
satisfy markdownlint MD051.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a4d3cd01-c7e3-487b-b8a9-4d547a8eac79

📥 Commits

Reviewing files that changed from the base of the PR and between bb59f12 and aa00b58.

⛔ Files ignored due to path filters (3)
  • config/crd/bases/formance.com_otelexporterendpoints.yaml is excluded by !**/*.yaml
  • docs/09-Configuration reference/settings.catalog.json is excluded by !**/*.json
  • helm/crds/templates/crds/apiextensions.k8s.io_v1_customresourcedefinition_otelexporterendpoints.formance.com.yaml is excluded by !**/*.yaml
📒 Files selected for processing (9)
  • api/formance.com/v1beta1/otelexporterendpoint_types.go
  • cmd/main.go
  • docs/09-Configuration reference/02-Custom Resource Definitions.md
  • internal/core/platform.go
  • internal/resources/otelexporterendpoints/collector_config.go
  • internal/resources/otelexporterendpoints/collector_config_test.go
  • internal/resources/otelexporterendpoints/init.go
  • internal/resources/settings/opentelemetry.go
  • internal/tests/otelexporterendpoint_controller_test.go
🚧 Files skipped from review as they are similar to previous changes (6)
  • cmd/main.go
  • internal/core/platform.go
  • api/formance.com/v1beta1/otelexporterendpoint_types.go
  • internal/resources/otelexporterendpoints/collector_config_test.go
  • internal/resources/otelexporterendpoints/collector_config.go
  • internal/resources/otelexporterendpoints/init.go

Comment thread internal/tests/otelexporterendpoint_controller_test.go
@sofiasimdianova sofiasimdianova force-pushed the feat/otelexportercrd-support branch from aa00b58 to b369969 Compare June 4, 2026 16:28
@sofiasimdianova sofiasimdianova requested a review from flemzord June 4, 2026 16:34
Copy link
Copy Markdown
Member

@flemzord flemzord left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Follow-up review after the latest force-push. I resolved obsolete threads and opened focused comments for the remaining current risks.

if err != nil {
return fmt.Errorf("creating ResourceReference for secret %q in stack %q: %w", ref.SecretName, stack.Name, err)
}
if !rr.Status.Ready {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The pre-existing Secret path is fine, but this fallback path can still stall. When the Secret is missing, this creates a ResourceReference and returns NewPendingError(). I do not see an OtelExporterEndpoint watch on the created ResourceReference or on the replicated Secret, and application errors do not requeue automatically here. Once the RR controller marks this RR Ready, the endpoint may not reconcile again until an unrelated Stack/Settings/endpoint event happens. Please add a watch/requeue for these RR/Secret updates and cover the fallback with an envtest that starts from a source Secret labelled formance.com/stack=any.

b.Watches(&v1beta1.Settings{}, handler.EnqueueRequestsFromMapFunc(
func(_ context.Context, obj client.Object) []reconcile.Request {
s := obj.(*v1beta1.Settings)
if !strings.HasPrefix(s.Spec.Key, "opentelemetry.") {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This predicate fixes the previous global fan-out, but it drops valid wildcard Settings keys. The Settings resolver accepts wildcards per segment, so keys like *.traces.dsn, opentelemetry.*.dsn, or *.metrics.resource-attributes can affect the OTEL values read by this controller without starting with opentelemetry.. Please match the supported OTEL key patterns using the same segment/wildcard semantics instead of a string prefix.

type OtelSignalConfig struct {
// Endpoint URL for the signal (e.g., "http://my-collector:4318", "grpc://my-collector:4317").
// Protocol is inferred from the URL scheme. HTTP/protobuf is the default for firewall compatibility.
// +kubebuilder:validation:MinLength=1
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MinLength still allows unsupported or ambiguous endpoint schemes. The config builder treats only grpc:// as gRPC and sends everything else through the HTTP exporter, so values like ftp://collector, typos, or bare host:port can be accepted at admission and fail later in the collector. Please validate allowed schemes (http, https, grpc) or explicitly normalize/document bare host:port before generating the collector config.

podAnnotations["secret-hash"] = secretHashes
}

replicas := int32(1)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The added resources/probes/securityContext are a useful improvement, but the collector runtime policy is still hard-coded here: one replica, fixed requests/limits, fixed probes/securityContext, and no scheduling/PDB/serviceAccount/imagePullSecret knobs. If this is intentionally phase-one behavior, please document that limitation clearly; otherwise expose a collector policy through Helm/platform settings before relying on this in production.


condition := v1beta1.NewCondition("CollectorsReady", endpoint.GetGeneration())
if len(pendingStacks) > 0 {
condition.Fail(fmt.Sprintf("waiting for collectors in: %s", strings.Join(pendingStacks, ", ")))
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This condition now waits for Deployment availability, which is good, but the message remains hard to act on when the collector fails to start. For config errors, image pull failures, CrashLoopBackOff, or failed health checks, users will only see the stack name here and need to inspect Pods manually. Consider surfacing the relevant Deployment condition or latest Pod waiting reason in status.info/the condition message.

| Field | Description | Default | Validation |
| --- | --- | --- | --- |
| `stackSelector` _[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#labelselector-v1-meta)_ | StackSelector is a standard Kubernetes LabelSelector (matchLabels/matchExpressions).<br />One CRD can target all current and future stacks with a single selector.<br />Matches the pattern established by Settings. | | |
| `traces` _[OtelSignalConfig](#otelsignalconfig)_ | Traces configures the traces signal. At least one of traces or metrics must be set.<br />Logs are intentionally out of scope. | | |
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These links still point to #otelsignalconfig, but the generated document does not define an OtelSignalConfig section. status.stacks is now documented, so that part is fixed; this remaining doc issue is specifically the missing OtelSignalConfig/OtelAuthConfig generated sections or broken anchors.

// Type is the authentication type.
// +kubebuilder:validation:Enum=bearer
Type string `json:"type"`
// FromSecret references a Secret name (expected key is "token").
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should not hardcode the key and should add a FromSecretKey property.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants