From 58bbdaf713bda277d5b1d5bda71d97e428b743b7 Mon Sep 17 00:00:00 2001 From: Asish Kumar Date: Thu, 14 May 2026 12:11:25 +0530 Subject: [PATCH 1/3] refactor(controller): drive policy-server metrics port via CLI flag The controller exposed exactly one piece of its configuration through an environment variable, `KUBEWARDEN_POLICY_SERVER_SERVICES_METRICS_PORT`, while every other knob already lived behind a `flag.*` CLI flag. The mismatch made the documentation harder to keep consistent and forced the Helm chart to use a different mechanism for this single setting. This commit moves the configuration onto the existing CLI surface: - `cmd/controller/main.go` registers a new `--policy-server-metrics-port` integer flag (default `constants.PolicyServerMetricsPort`, range `1`-`65535`, validated with the same pattern as `--webhook-server-port`), and drops the `os.Getenv` block plus the now-unused `strconv` import. The unused `gocognit` nolint on `main()` is removed because trimming the env-var parser brings the function under the threshold. - `internal/constants/constants.go` drops the `PolicyServerMetricsPortEnvVar` constant; nothing else referenced it. - The PolicyServer CRD doc comment in `api/policies/v1/policyserver_types.go` now points users at the new flag, and the generated CRD YAML (`charts/kubewarden-crds/templates/crds/policies.kubewarden.io_policyservers.yaml`) and CRD docs (`docs/crds/CRD-docs-for-docs-repo.{adoc,md}`) are regenerated. - `charts/kubewarden-controller/templates/deployment.yaml` emits `--policy-server-metrics-port=...` inside the existing sidecar-mode args block (where the env var was set previously), and drops the matching `env:` entry. - The two helm-unittest assertions in `charts/kubewarden-controller/tests/telemetry_configuration_test.yaml` that pinned the env-var name are rewritten as `args:` assertions for the new flag. - The comments in `internal/controller/policyserver_controller.go` and `internal/controller/policyserver_controller_service_test.go` are refreshed to describe the priority chain in terms of the CLI flag. Operators who run the controller binary directly with the old env var set will need to switch to `--policy-server-metrics-port=`; this breaking change is intentional and matches the request in the issue. The Helm chart upgrade is transparent because the chart already drives both ends. Closes #787 Signed-off-by: Asish Kumar --- api/policies/v1/policyserver_types.go | 2 +- .../templates/deployment.yaml | 5 ++- .../tests/telemetry_configuration_test.yaml | 10 ++--- .../policies.kubewarden.io_policyservers.yaml | 2 +- cmd/controller/main.go | 45 ++++++++----------- docs/crds/CRD-docs-for-docs-repo.adoc | 2 +- docs/crds/CRD-docs-for-docs-repo.md | 2 +- internal/constants/constants.go | 1 - .../controller/policyserver_controller.go | 4 +- .../policyserver_controller_service_test.go | 10 ++--- 10 files changed, 37 insertions(+), 46 deletions(-) diff --git a/api/policies/v1/policyserver_types.go b/api/policies/v1/policyserver_types.go index 52cd73b13..0902f0052 100644 --- a/api/policies/v1/policyserver_types.go +++ b/api/policies/v1/policyserver_types.go @@ -175,7 +175,7 @@ type PolicyServerSpec struct { // Port exposed by the metrics Service for this policy server. // When unset, defaults to the controller-wide default - // (KUBEWARDEN_POLICY_SERVER_SERVICES_METRICS_PORT env var, or 8080). + // (--policy-server-metrics-port CLI flag, or 8080). // Only relevant when metrics are enabled. // // Use this field to customize which port Prometheus scrapes for this diff --git a/charts/kubewarden-controller/templates/deployment.yaml b/charts/kubewarden-controller/templates/deployment.yaml index 290c8e2f1..19687a553 100644 --- a/charts/kubewarden-controller/templates/deployment.yaml +++ b/charts/kubewarden-controller/templates/deployment.yaml @@ -82,6 +82,9 @@ spec: {{- if or .Values.telemetry.metrics .Values.telemetry.tracing }} {{- if and (eq .Values.telemetry.mode "sidecar") }} - --enable-otel-sidecar + {{- if .Values.telemetry.metrics }} + - --policy-server-metrics-port={{ .Values.telemetry.sidecar.metrics.port | default 8080 }} + {{- end }} {{- end }} {{- if .Values.telemetry.metrics }} - --enable-metrics @@ -100,8 +103,6 @@ spec: - /controller env: {{- if and .Values.telemetry.metrics (eq .Values.telemetry.mode "sidecar") }} - - name: KUBEWARDEN_POLICY_SERVER_SERVICES_METRICS_PORT - value: "{{ .Values.telemetry.sidecar.metrics.port | default 8080 }}" - name: OTEL_EXPORTER_OTLP_ENDPOINT value: "https://localhost:4317" - name: OTEL_EXPORTER_OTLP_INSECURE diff --git a/charts/kubewarden-controller/tests/telemetry_configuration_test.yaml b/charts/kubewarden-controller/tests/telemetry_configuration_test.yaml index 4339e11b8..953ef4dba 100644 --- a/charts/kubewarden-controller/tests/telemetry_configuration_test.yaml +++ b/charts/kubewarden-controller/tests/telemetry_configuration_test.yaml @@ -37,10 +37,9 @@ tests: content: --opentelemetry-client-certificate-secret=my-client-cert - notContains: - path: spec.template.spec.containers[0].env + path: spec.template.spec.containers[0].args content: - name: KUBEWARDEN_POLICY_SERVER_SERVICES_METRICS_PORT - value: "8080" + --policy-server-metrics-port=8080 - contains: path: spec.template.spec.containers[0].env content: @@ -138,10 +137,9 @@ tests: content: --opentelemetry-client-certificate-secret= - contains: - path: spec.template.spec.containers[0].env + path: spec.template.spec.containers[0].args content: - name: KUBEWARDEN_POLICY_SERVER_SERVICES_METRICS_PORT - value: "8080" + --policy-server-metrics-port=8080 - contains: path: spec.template.spec.containers[0].env content: diff --git a/charts/kubewarden-crds/templates/crds/policies.kubewarden.io_policyservers.yaml b/charts/kubewarden-crds/templates/crds/policies.kubewarden.io_policyservers.yaml index 0b0bf5d2b..ed0380060 100644 --- a/charts/kubewarden-crds/templates/crds/policies.kubewarden.io_policyservers.yaml +++ b/charts/kubewarden-crds/templates/crds/policies.kubewarden.io_policyservers.yaml @@ -1177,7 +1177,7 @@ spec: description: |- Port exposed by the metrics Service for this policy server. When unset, defaults to the controller-wide default - (KUBEWARDEN_POLICY_SERVER_SERVICES_METRICS_PORT env var, or 8080). + (--policy-server-metrics-port CLI flag, or 8080). Only relevant when metrics are enabled. Use this field to customize which port Prometheus scrapes for this diff --git a/cmd/controller/main.go b/cmd/controller/main.go index d2ae3ad32..b21c42491 100644 --- a/cmd/controller/main.go +++ b/cmd/controller/main.go @@ -23,7 +23,6 @@ import ( "fmt" "os" "path/filepath" - "strconv" "strings" // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) @@ -103,7 +102,7 @@ func init() { //+kubebuilder:scaffold:scheme } -//nolint:funlen,gocognit // Avoid splitting the main function in multiple functions to avoid changing the retcode logic for metrics shutdown +//nolint:funlen // Avoid splitting the main function in multiple functions to avoid changing the retcode logic for metrics shutdown func main() { retcode := 0 defer func() { os.Exit(retcode) }() @@ -120,6 +119,10 @@ func main() { flag.StringVar(&mgrOpts.MetricsAddr, "metrics-bind-address", ":8088", "The address the controller-runtime metric endpoint binds to.") flag.StringVar(&mgrOpts.ProbeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.") flag.IntVar(&mgrOpts.WebhookServerPort, "webhook-server-port", 9443, "The port the webhook server listens on.") + policyServerMetricsPortFlag := flag.Int("policy-server-metrics-port", + constants.PolicyServerMetricsPort, + "The default port exposed by every PolicyServer metrics Service. "+ + "Per-PolicyServer overrides (spec.metricsPort) always take priority.") flag.BoolVar(&mgrOpts.EnableLeaderElection, "leader-elect", false, "Enable leader election for controller manager. "+ "Enabling this will ensure there is only one active controller manager.") @@ -195,31 +198,21 @@ func main() { "Use only when the Kubernetes API server cannot reach pod-network webhook endpoints.") } - // Read the global default metrics port for PolicyServer services from the - // environment variable, falling back to the hardcoded constant. - policyServerMetricsPort := int32(constants.PolicyServerMetricsPort) - if envPort := os.Getenv(constants.PolicyServerMetricsPortEnvVar); envPort != "" { - parsed, err := strconv.ParseInt(envPort, 10, 32) - if err != nil { - setupLog.Error(err, "cannot parse env var as integer port", - "envVar", constants.PolicyServerMetricsPortEnvVar, "value", envPort) - retcode = 1 - return - } - if parsed < minAllowedPort || parsed > maxAllowedPort { - setupLog.Error( - errors.New("port must be between 1 and 65535"), - "invalid env var port value", - "envVar", constants.PolicyServerMetricsPortEnvVar, - "value", envPort, - "min", minAllowedPort, - "max", maxAllowedPort, - ) - retcode = 1 - return - } - policyServerMetricsPort = int32(parsed) + // Validate --policy-server-metrics-port range. + if int64(*policyServerMetricsPortFlag) < minAllowedPort || + int64(*policyServerMetricsPortFlag) > maxAllowedPort { + setupLog.Error( + errors.New("port must be between 1 and 65535"), + "invalid policy server metrics port", + "flag", "--policy-server-metrics-port", + "value", *policyServerMetricsPortFlag, + "min", minAllowedPort, + "max", maxAllowedPort, + ) + retcode = 1 + return } + policyServerMetricsPort := int32(*policyServerMetricsPortFlag) if enableMetrics { shutdown, err := metrics.New() diff --git a/docs/crds/CRD-docs-for-docs-repo.adoc b/docs/crds/CRD-docs-for-docs-repo.adoc index 370a7a659..055551770 100644 --- a/docs/crds/CRD-docs-for-docs-repo.adoc +++ b/docs/crds/CRD-docs-for-docs-repo.adoc @@ -959,7 +959,7 @@ Optional: \{} + | *`metricsPort`* __integer__ | Port exposed by the metrics Service for this policy server. + When unset, defaults to the controller-wide default + -(KUBEWARDEN_POLICY_SERVER_SERVICES_METRICS_PORT env var, or 8080). + +(--policy-server-metrics-port CLI flag, or 8080). + Only relevant when metrics are enabled. + Use this field to customize which port Prometheus scrapes for this + diff --git a/docs/crds/CRD-docs-for-docs-repo.md b/docs/crds/CRD-docs-for-docs-repo.md index 0c78a1c4b..88c996acb 100644 --- a/docs/crds/CRD-docs-for-docs-repo.md +++ b/docs/crds/CRD-docs-for-docs-repo.md @@ -542,7 +542,7 @@ _Appears in:_ | `namespacedPoliciesCapabilities` _string array_ | NamespacedPoliciesCapabilities lists host capability API calls allowed
for namespaced policies running on this PolicyServer. When not set,
no host capabilities are granted to namespaced policies.
Supported wildcard patterns:
- "*": allow all host capabilities
- "category/*": allow all capabilities in a category (e.g. "oci/*")
- "category/version/*": allow all capabilities of a specific version (e.g. "oci/v1/*")
- Specific capability paths (e.g. "oci/v1/verify", "net/v1/dns_lookup_host") | | Optional: \{\}
| | `webhookPort` _integer_ | Port where the policy server listens for incoming webhook requests.
When unset, defaults to 8443. This is the port the Kubernetes API server
reaches when evaluating admission requests. | | Maximum: 65535
Minimum: 1
Optional: \{\}
| | `readinessProbePort` _integer_ | Port used by the policy server to expose the readiness probe endpoint.
When unset, defaults to 8081. | | Maximum: 65535
Minimum: 1
Optional: \{\}
| -| `metricsPort` _integer_ | Port exposed by the metrics Service for this policy server.
When unset, defaults to the controller-wide default
(KUBEWARDEN_POLICY_SERVER_SERVICES_METRICS_PORT env var, or 8080).
Only relevant when metrics are enabled.
Use this field to customize which port Prometheus scrapes for this
PolicyServer's metrics Service (e.g. to match naming conventions or
avoid Service-level port collisions).
NOTE: this field controls only the Service Port (the externally visible
scrape port). The Service TargetPort — the port the pod actually listens
on — is always the controller-wide default and is not affected by this
field. This is intentional: when the OpenTelemetry sidecar mode is
enabled, each pod gets its own injected sidecar, but the pod-side
Prometheus listener port is determined by controller-wide/injection
configuration, not per PolicyServer. Therefore, changing this field does
not change the pod listener port and will not resolve pod-port conflicts
such as those caused by hostNetwork. | | Maximum: 65535
Minimum: 1
Optional: \{\}
| +| `metricsPort` _integer_ | Port exposed by the metrics Service for this policy server.
When unset, defaults to the controller-wide default
(--policy-server-metrics-port CLI flag, or 8080).
Only relevant when metrics are enabled.
Use this field to customize which port Prometheus scrapes for this
PolicyServer's metrics Service (e.g. to match naming conventions or
avoid Service-level port collisions).
NOTE: this field controls only the Service Port (the externally visible
scrape port). The Service TargetPort — the port the pod actually listens
on — is always the controller-wide default and is not affected by this
field. This is intentional: when the OpenTelemetry sidecar mode is
enabled, each pod gets its own injected sidecar, but the pod-side
Prometheus listener port is determined by controller-wide/injection
configuration, not per PolicyServer. Therefore, changing this field does
not change the pod listener port and will not resolve pod-port conflicts
such as those caused by hostNetwork. | | Maximum: 65535
Minimum: 1
Optional: \{\}
| diff --git a/internal/constants/constants.go b/internal/constants/constants.go index 586e3857d..066fdf057 100644 --- a/internal/constants/constants.go +++ b/internal/constants/constants.go @@ -12,7 +12,6 @@ const ( PolicyServerDeploymentPodSpecConfigVersionLabel = "kubewarden/config-version" PolicyServerListenPort = 8443 PolicyServerServicePort = 443 - PolicyServerMetricsPortEnvVar = "KUBEWARDEN_POLICY_SERVER_SERVICES_METRICS_PORT" PolicyServerMetricsPort = 8080 PolicyServerReadinessProbePort = 8081 PolicyServerReadinessProbe = "/readiness" diff --git a/internal/controller/policyserver_controller.go b/internal/controller/policyserver_controller.go index b8a2d042b..308ef9b8b 100644 --- a/internal/controller/policyserver_controller.go +++ b/internal/controller/policyserver_controller.go @@ -75,8 +75,8 @@ type PolicyServerReconciler struct { // so that in-cluster DNS resolution keeps working. HostNetwork bool // PolicyServerMetricsPort is the global default metrics port for PolicyServer - // Service objects. It is populated from the KUBEWARDEN_POLICY_SERVER_SERVICES_METRICS_PORT - // environment variable at startup, falling back to constants.PolicyServerMetricsPort. + // Service objects. It is populated from the --policy-server-metrics-port CLI + // flag at startup, falling back to constants.PolicyServerMetricsPort. // A per-PolicyServer CRD field (spec.metricsPort) always takes priority. PolicyServerMetricsPort int32 } diff --git a/internal/controller/policyserver_controller_service_test.go b/internal/controller/policyserver_controller_service_test.go index 7c34b4022..a65885774 100644 --- a/internal/controller/policyserver_controller_service_test.go +++ b/internal/controller/policyserver_controller_service_test.go @@ -72,7 +72,7 @@ func findServicePort(ports []corev1.ServicePort, name string) *corev1.ServicePor // TestUpdateServiceMetricsPortPriorityChain validates the 3-tier priority // chain for the metrics Service Port: // -// CRD field (spec.metricsPort) > env var (PolicyServerMetricsPort) > constant (8080) +// CRD field (spec.metricsPort) > --policy-server-metrics-port CLI flag > constant (8080) // // It also verifies that the Service TargetPort is always fixed at the // controller-wide PolicyServerMetricsPort regardless of any CRD override. @@ -87,14 +87,14 @@ func TestUpdateServiceMetricsPortPriorityChain(t *testing.T) { tests := []struct { name string metricsEnabled bool - policyServerMetricPort int32 // simulates env var / constant + policyServerMetricPort int32 // simulates --policy-server-metrics-port CLI flag / constant crdMetricsPort *int32 expectMetricsPort bool expectedPort int32 // Service Port expectedTargetPort int32 // Service TargetPort }{ { - name: "env var only (no CRD override)", + name: "CLI flag only (no CRD override)", metricsEnabled: true, policyServerMetricPort: 9090, crdMetricsPort: nil, @@ -103,7 +103,7 @@ func TestUpdateServiceMetricsPortPriorityChain(t *testing.T) { expectedTargetPort: 9090, }, { - name: "CRD overrides env var", + name: "CRD overrides CLI flag", metricsEnabled: true, policyServerMetricPort: 9090, crdMetricsPort: int32Ptr(9091), @@ -170,7 +170,7 @@ func TestUpdateServiceMetricsPortPriorityChain(t *testing.T) { require.NotNil(t, metricsPort, "metrics port must exist when metrics are enabled") assert.Equal(t, tc.expectedPort, metricsPort.Port, - "Service Port should respect CRD > env var > constant priority") + "Service Port should respect CRD > CLI flag > constant priority") assert.Equal(t, intstr.FromInt32(tc.expectedTargetPort), metricsPort.TargetPort, "Service TargetPort must always equal the global PolicyServerMetricsPort (fixed regardless of spec.metricsPort, to avoid breaking OTel sidecar mode)") assert.Equal(t, corev1.ProtocolTCP, metricsPort.Protocol) From 0bae37d794a4747746ce24ec90e1f7ecd4e8c372 Mon Sep 17 00:00:00 2001 From: Asish Kumar Date: Thu, 14 May 2026 22:15:54 +0530 Subject: [PATCH 2/3] fix(controller): keep deprecated metrics port env fallback Signed-off-by: Asish Kumar --- api/policies/v1/policyserver_types.go | 2 +- .../policies.kubewarden.io_policyservers.yaml | 2 +- cmd/controller/main.go | 44 ++++++++++++++++++- docs/crds/CRD-docs-for-docs-repo.adoc | 3 +- docs/crds/CRD-docs-for-docs-repo.md | 3 +- internal/constants/constants.go | 1 + .../controller/policyserver_controller.go | 4 +- .../policyserver_controller_service_test.go | 4 +- 8 files changed, 53 insertions(+), 10 deletions(-) diff --git a/api/policies/v1/policyserver_types.go b/api/policies/v1/policyserver_types.go index 0902f0052..413d8034e 100644 --- a/api/policies/v1/policyserver_types.go +++ b/api/policies/v1/policyserver_types.go @@ -175,7 +175,7 @@ type PolicyServerSpec struct { // Port exposed by the metrics Service for this policy server. // When unset, defaults to the controller-wide default - // (--policy-server-metrics-port CLI flag, or 8080). + // (--policy-server-metrics-port CLI flag, deprecated KUBEWARDEN_POLICY_SERVER_SERVICES_METRICS_PORT env var, or 8080). // Only relevant when metrics are enabled. // // Use this field to customize which port Prometheus scrapes for this diff --git a/charts/kubewarden-crds/templates/crds/policies.kubewarden.io_policyservers.yaml b/charts/kubewarden-crds/templates/crds/policies.kubewarden.io_policyservers.yaml index ed0380060..106132fb3 100644 --- a/charts/kubewarden-crds/templates/crds/policies.kubewarden.io_policyservers.yaml +++ b/charts/kubewarden-crds/templates/crds/policies.kubewarden.io_policyservers.yaml @@ -1177,7 +1177,7 @@ spec: description: |- Port exposed by the metrics Service for this policy server. When unset, defaults to the controller-wide default - (--policy-server-metrics-port CLI flag, or 8080). + (--policy-server-metrics-port CLI flag, deprecated KUBEWARDEN_POLICY_SERVER_SERVICES_METRICS_PORT env var, or 8080). Only relevant when metrics are enabled. Use this field to customize which port Prometheus scrapes for this diff --git a/cmd/controller/main.go b/cmd/controller/main.go index b21c42491..84e5e8ad5 100644 --- a/cmd/controller/main.go +++ b/cmd/controller/main.go @@ -23,6 +23,7 @@ import ( "fmt" "os" "path/filepath" + "strconv" "strings" // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) @@ -102,7 +103,7 @@ func init() { //+kubebuilder:scaffold:scheme } -//nolint:funlen // Avoid splitting the main function in multiple functions to avoid changing the retcode logic for metrics shutdown +//nolint:funlen,gocognit // Avoid splitting the main function in multiple functions to avoid changing the retcode logic for metrics shutdown func main() { retcode := 0 defer func() { os.Exit(retcode) }() @@ -162,6 +163,12 @@ func main() { opts := zap.Options{} opts.BindFlags(flag.CommandLine) flag.Parse() + policyServerMetricsPortFlagSet := false + flag.Visit(func(f *flag.Flag) { + if f.Name == "policy-server-metrics-port" { + policyServerMetricsPortFlagSet = true + } + }) mgrOpts.EnableMutualTLS = config.ClientCAConfigMapName != "" config.ImagePullSecrets = parseImagePullSecrets(imagePullSecretsFlag) ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts))) @@ -213,6 +220,41 @@ func main() { return } policyServerMetricsPort := int32(*policyServerMetricsPortFlag) + if envPort := os.Getenv(constants.PolicyServerMetricsPortEnvVar); envPort != "" { + if policyServerMetricsPortFlagSet { + setupLog.Info( + "WARNING: deprecated environment variable ignored because --policy-server-metrics-port was set", + "envVar", constants.PolicyServerMetricsPortEnvVar, + "flag", "--policy-server-metrics-port", + ) + } else { + envPortParsed, err := strconv.ParseInt(envPort, 10, 32) + if err != nil { + setupLog.Error(err, "invalid policy server metrics port environment variable", + "envVar", constants.PolicyServerMetricsPortEnvVar, "value", envPort) + retcode = 1 + return + } + policyServerMetricsPort = int32(envPortParsed) + setupLog.Info( + "WARNING: deprecated environment variable used as fallback; use --policy-server-metrics-port instead", + "envVar", constants.PolicyServerMetricsPortEnvVar, + "flag", "--policy-server-metrics-port", + ) + } + } + if int64(policyServerMetricsPort) < minAllowedPort || + int64(policyServerMetricsPort) > maxAllowedPort { + setupLog.Error( + errors.New("port must be between 1 and 65535"), + "invalid policy server metrics port", + "value", policyServerMetricsPort, + "min", minAllowedPort, + "max", maxAllowedPort, + ) + retcode = 1 + return + } if enableMetrics { shutdown, err := metrics.New() diff --git a/docs/crds/CRD-docs-for-docs-repo.adoc b/docs/crds/CRD-docs-for-docs-repo.adoc index 055551770..2fc6645ee 100644 --- a/docs/crds/CRD-docs-for-docs-repo.adoc +++ b/docs/crds/CRD-docs-for-docs-repo.adoc @@ -959,7 +959,7 @@ Optional: \{} + | *`metricsPort`* __integer__ | Port exposed by the metrics Service for this policy server. + When unset, defaults to the controller-wide default + -(--policy-server-metrics-port CLI flag, or 8080). + +(--policy-server-metrics-port CLI flag, deprecated KUBEWARDEN_POLICY_SERVER_SERVICES_METRICS_PORT env var, or 8080). + Only relevant when metrics are enabled. + Use this field to customize which port Prometheus scrapes for this + @@ -1588,4 +1588,3 @@ _Underlying type:_ _string_ - diff --git a/docs/crds/CRD-docs-for-docs-repo.md b/docs/crds/CRD-docs-for-docs-repo.md index 88c996acb..8f8cf572d 100644 --- a/docs/crds/CRD-docs-for-docs-repo.md +++ b/docs/crds/CRD-docs-for-docs-repo.md @@ -542,7 +542,7 @@ _Appears in:_ | `namespacedPoliciesCapabilities` _string array_ | NamespacedPoliciesCapabilities lists host capability API calls allowed
for namespaced policies running on this PolicyServer. When not set,
no host capabilities are granted to namespaced policies.
Supported wildcard patterns:
- "*": allow all host capabilities
- "category/*": allow all capabilities in a category (e.g. "oci/*")
- "category/version/*": allow all capabilities of a specific version (e.g. "oci/v1/*")
- Specific capability paths (e.g. "oci/v1/verify", "net/v1/dns_lookup_host") | | Optional: \{\}
| | `webhookPort` _integer_ | Port where the policy server listens for incoming webhook requests.
When unset, defaults to 8443. This is the port the Kubernetes API server
reaches when evaluating admission requests. | | Maximum: 65535
Minimum: 1
Optional: \{\}
| | `readinessProbePort` _integer_ | Port used by the policy server to expose the readiness probe endpoint.
When unset, defaults to 8081. | | Maximum: 65535
Minimum: 1
Optional: \{\}
| -| `metricsPort` _integer_ | Port exposed by the metrics Service for this policy server.
When unset, defaults to the controller-wide default
(--policy-server-metrics-port CLI flag, or 8080).
Only relevant when metrics are enabled.
Use this field to customize which port Prometheus scrapes for this
PolicyServer's metrics Service (e.g. to match naming conventions or
avoid Service-level port collisions).
NOTE: this field controls only the Service Port (the externally visible
scrape port). The Service TargetPort — the port the pod actually listens
on — is always the controller-wide default and is not affected by this
field. This is intentional: when the OpenTelemetry sidecar mode is
enabled, each pod gets its own injected sidecar, but the pod-side
Prometheus listener port is determined by controller-wide/injection
configuration, not per PolicyServer. Therefore, changing this field does
not change the pod listener port and will not resolve pod-port conflicts
such as those caused by hostNetwork. | | Maximum: 65535
Minimum: 1
Optional: \{\}
| +| `metricsPort` _integer_ | Port exposed by the metrics Service for this policy server.
When unset, defaults to the controller-wide default
(--policy-server-metrics-port CLI flag, deprecated KUBEWARDEN_POLICY_SERVER_SERVICES_METRICS_PORT env var, or 8080).
Only relevant when metrics are enabled.
Use this field to customize which port Prometheus scrapes for this
PolicyServer's metrics Service (e.g. to match naming conventions or
avoid Service-level port collisions).
NOTE: this field controls only the Service Port (the externally visible
scrape port). The Service TargetPort — the port the pod actually listens
on — is always the controller-wide default and is not affected by this
field. This is intentional: when the OpenTelemetry sidecar mode is
enabled, each pod gets its own injected sidecar, but the pod-side
Prometheus listener port is determined by controller-wide/injection
configuration, not per PolicyServer. Therefore, changing this field does
not change the pod listener port and will not resolve pod-port conflicts
such as those caused by hostNetwork. | | Maximum: 65535
Minimum: 1
Optional: \{\}
| @@ -878,4 +878,3 @@ _Appears in:_ - diff --git a/internal/constants/constants.go b/internal/constants/constants.go index 066fdf057..586e3857d 100644 --- a/internal/constants/constants.go +++ b/internal/constants/constants.go @@ -12,6 +12,7 @@ const ( PolicyServerDeploymentPodSpecConfigVersionLabel = "kubewarden/config-version" PolicyServerListenPort = 8443 PolicyServerServicePort = 443 + PolicyServerMetricsPortEnvVar = "KUBEWARDEN_POLICY_SERVER_SERVICES_METRICS_PORT" PolicyServerMetricsPort = 8080 PolicyServerReadinessProbePort = 8081 PolicyServerReadinessProbe = "/readiness" diff --git a/internal/controller/policyserver_controller.go b/internal/controller/policyserver_controller.go index 308ef9b8b..baaaec487 100644 --- a/internal/controller/policyserver_controller.go +++ b/internal/controller/policyserver_controller.go @@ -76,7 +76,9 @@ type PolicyServerReconciler struct { HostNetwork bool // PolicyServerMetricsPort is the global default metrics port for PolicyServer // Service objects. It is populated from the --policy-server-metrics-port CLI - // flag at startup, falling back to constants.PolicyServerMetricsPort. + // flag at startup, falling back to the deprecated + // KUBEWARDEN_POLICY_SERVER_SERVICES_METRICS_PORT env var and then to + // constants.PolicyServerMetricsPort. // A per-PolicyServer CRD field (spec.metricsPort) always takes priority. PolicyServerMetricsPort int32 } diff --git a/internal/controller/policyserver_controller_service_test.go b/internal/controller/policyserver_controller_service_test.go index a65885774..56eaacbfb 100644 --- a/internal/controller/policyserver_controller_service_test.go +++ b/internal/controller/policyserver_controller_service_test.go @@ -72,7 +72,7 @@ func findServicePort(ports []corev1.ServicePort, name string) *corev1.ServicePor // TestUpdateServiceMetricsPortPriorityChain validates the 3-tier priority // chain for the metrics Service Port: // -// CRD field (spec.metricsPort) > --policy-server-metrics-port CLI flag > constant (8080) +// CRD field (spec.metricsPort) > --policy-server-metrics-port CLI flag > deprecated env var > constant (8080) // // It also verifies that the Service TargetPort is always fixed at the // controller-wide PolicyServerMetricsPort regardless of any CRD override. @@ -87,7 +87,7 @@ func TestUpdateServiceMetricsPortPriorityChain(t *testing.T) { tests := []struct { name string metricsEnabled bool - policyServerMetricPort int32 // simulates --policy-server-metrics-port CLI flag / constant + policyServerMetricPort int32 // simulates controller-wide CLI flag / env var / constant crdMetricsPort *int32 expectMetricsPort bool expectedPort int32 // Service Port From f3190f5f0ead8e85ed7aca3f54650937a2711546 Mon Sep 17 00:00:00 2001 From: Asish Kumar Date: Fri, 15 May 2026 12:06:26 +0530 Subject: [PATCH 3/3] fix(controller): address metrics port review feedback Signed-off-by: Asish Kumar --- .../templates/deployment.yaml | 4 ++-- .../tests/telemetry_configuration_test.yaml | 23 +++++++++++++++++++ cmd/controller/main.go | 15 ++++++------ 3 files changed, 33 insertions(+), 9 deletions(-) diff --git a/charts/kubewarden-controller/templates/deployment.yaml b/charts/kubewarden-controller/templates/deployment.yaml index 19687a553..abdab6bf9 100644 --- a/charts/kubewarden-controller/templates/deployment.yaml +++ b/charts/kubewarden-controller/templates/deployment.yaml @@ -82,9 +82,9 @@ spec: {{- if or .Values.telemetry.metrics .Values.telemetry.tracing }} {{- if and (eq .Values.telemetry.mode "sidecar") }} - --enable-otel-sidecar - {{- if .Values.telemetry.metrics }} + {{- end }} + {{- if and .Values.telemetry.metrics (eq .Values.telemetry.mode "sidecar") }} - --policy-server-metrics-port={{ .Values.telemetry.sidecar.metrics.port | default 8080 }} - {{- end }} {{- end }} {{- if .Values.telemetry.metrics }} - --enable-metrics diff --git a/charts/kubewarden-controller/tests/telemetry_configuration_test.yaml b/charts/kubewarden-controller/tests/telemetry_configuration_test.yaml index 953ef4dba..1d240ad13 100644 --- a/charts/kubewarden-controller/tests/telemetry_configuration_test.yaml +++ b/charts/kubewarden-controller/tests/telemetry_configuration_test.yaml @@ -200,3 +200,26 @@ tests: path: tls.crt - key: tls.key path: tls.key + - it: "sidecar tracing should not set policy server metrics port when metrics are disabled" + set: + telemetry: + mode: "sidecar" + metrics: false + tracing: true + asserts: + - contains: + path: spec.template.spec.containers[0].args + content: + --enable-otel-sidecar + - notContains: + path: spec.template.spec.containers[0].args + content: + --enable-metrics + - contains: + path: spec.template.spec.containers[0].args + content: + --enable-tracing + - notContains: + path: spec.template.spec.containers[0].args + content: + --policy-server-metrics-port=8080 diff --git a/cmd/controller/main.go b/cmd/controller/main.go index 84e5e8ad5..f5c614f79 100644 --- a/cmd/controller/main.go +++ b/cmd/controller/main.go @@ -116,11 +116,13 @@ func main() { var openTelemetryClientCertificateSecret string var openTelemetryCertificateSecret string var imagePullSecretsFlag string + var policyServerMetricsPort int flag.StringVar(&mgrOpts.MetricsAddr, "metrics-bind-address", ":8088", "The address the controller-runtime metric endpoint binds to.") flag.StringVar(&mgrOpts.ProbeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.") flag.IntVar(&mgrOpts.WebhookServerPort, "webhook-server-port", 9443, "The port the webhook server listens on.") - policyServerMetricsPortFlag := flag.Int("policy-server-metrics-port", + flag.IntVar(&policyServerMetricsPort, + "policy-server-metrics-port", constants.PolicyServerMetricsPort, "The default port exposed by every PolicyServer metrics Service. "+ "Per-PolicyServer overrides (spec.metricsPort) always take priority.") @@ -206,20 +208,19 @@ func main() { } // Validate --policy-server-metrics-port range. - if int64(*policyServerMetricsPortFlag) < minAllowedPort || - int64(*policyServerMetricsPortFlag) > maxAllowedPort { + if int64(policyServerMetricsPort) < minAllowedPort || + int64(policyServerMetricsPort) > maxAllowedPort { setupLog.Error( errors.New("port must be between 1 and 65535"), "invalid policy server metrics port", "flag", "--policy-server-metrics-port", - "value", *policyServerMetricsPortFlag, + "value", policyServerMetricsPort, "min", minAllowedPort, "max", maxAllowedPort, ) retcode = 1 return } - policyServerMetricsPort := int32(*policyServerMetricsPortFlag) if envPort := os.Getenv(constants.PolicyServerMetricsPortEnvVar); envPort != "" { if policyServerMetricsPortFlagSet { setupLog.Info( @@ -235,7 +236,7 @@ func main() { retcode = 1 return } - policyServerMetricsPort = int32(envPortParsed) + policyServerMetricsPort = int(envPortParsed) setupLog.Info( "WARNING: deprecated environment variable used as fallback; use --policy-server-metrics-port instead", "envVar", constants.PolicyServerMetricsPortEnvVar, @@ -302,7 +303,7 @@ func main() { mgrOpts.DeploymentsNamespace, config, otelConfiguration, - policyServerMetricsPort, + int32(policyServerMetricsPort), ); err != nil { setupLog.Error(err, "unable to create controllers") retcode = 1