Skip to content

Commit 106185b

Browse files
committed
Merge branch 'issue1658-hostnetwork-v2'
2 parents 88b4b9c + 5be5364 commit 106185b

28 files changed

Lines changed: 1150 additions & 96 deletions

Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ helm-unittest:
5454
test-e2e: controller-image audit-scanner-image policy-server-image
5555
$(GO_BUILD_ENV) go test ./e2e/ -v
5656

57+
.PHONY: test-all
58+
test-all: test helm-unittest test-e2e
59+
5760
.PHONY: fmt-go
5861
fmt-go:
5962
$(GO_BUILD_ENV) go fmt ./...

api/policies/v1/factories.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,9 @@ type PolicyServerBuilder struct {
486486
limits corev1.ResourceList
487487
requests corev1.ResourceList
488488
sigstoreTrustConfigMap string
489+
webhookPort *int32
490+
readinessProbePort *int32
491+
metricsPort *int32
489492
}
490493

491494
func NewPolicyServerFactory() *PolicyServerBuilder {
@@ -529,6 +532,21 @@ func (f *PolicyServerBuilder) WithRequests(requests corev1.ResourceList) *Policy
529532
return f
530533
}
531534

535+
func (f *PolicyServerBuilder) WithWebhookPort(port int32) *PolicyServerBuilder {
536+
f.webhookPort = &port
537+
return f
538+
}
539+
540+
func (f *PolicyServerBuilder) WithReadinessProbePort(port int32) *PolicyServerBuilder {
541+
f.readinessProbePort = &port
542+
return f
543+
}
544+
545+
func (f *PolicyServerBuilder) WithMetricsPort(port int32) *PolicyServerBuilder {
546+
f.metricsPort = &port
547+
return f
548+
}
549+
532550
func (f *PolicyServerBuilder) Build() *PolicyServer {
533551
policyServer := PolicyServer{
534552
ObjectMeta: metav1.ObjectMeta{
@@ -552,6 +570,9 @@ func (f *PolicyServerBuilder) Build() *PolicyServer {
552570
Limits: f.limits,
553571
Requests: f.requests,
554572
SigstoreTrustConfig: f.sigstoreTrustConfigMap,
573+
WebhookPort: f.webhookPort,
574+
ReadinessProbePort: f.readinessProbePort,
575+
MetricsPort: f.metricsPort,
555576
Env: []corev1.EnvVar{
556577
{
557578
Name: "KUBEWARDEN_LOG_LEVEL",

api/policies/v1/policyserver_types.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,28 @@ type PolicyServerSpec struct {
139139
// remain unchanged, but new pods that reference it cannot be created.
140140
// +optional
141141
PriorityClassName string `json:"priorityClassName,omitempty"`
142+
143+
// Port where the policy server listens for incoming webhook requests.
144+
// When unset, defaults to 8443. This is the port the Kubernetes API server
145+
// reaches when evaluating admission requests.
146+
// +optional
147+
// +kubebuilder:validation:Minimum=1
148+
// +kubebuilder:validation:Maximum=65535
149+
WebhookPort *int32 `json:"webhookPort,omitempty"`
150+
151+
// Port used by the policy server to expose the readiness probe endpoint.
152+
// When unset, defaults to 8081.
153+
// +optional
154+
// +kubebuilder:validation:Minimum=1
155+
// +kubebuilder:validation:Maximum=65535
156+
ReadinessProbePort *int32 `json:"readinessProbePort,omitempty"`
157+
158+
// Port used by the policy server to expose the metrics endpoint.
159+
// When unset, defaults to 8080. Only relevant when metrics are enabled.
160+
// +optional
161+
// +kubebuilder:validation:Minimum=1
162+
// +kubebuilder:validation:Maximum=65535
163+
MetricsPort *int32 `json:"metricsPort,omitempty"`
142164
}
143165

144166
type ReconciliationTransitionReason string
@@ -211,6 +233,34 @@ func (ps *PolicyServer) AppLabel() string {
211233
return "kubewarden-" + ps.NameWithPrefix()
212234
}
213235

236+
// EffectiveWebhookPort returns the port the policy server listens on for
237+
// admission webhook requests, using the CRD field when set or the default constant.
238+
func (ps *PolicyServer) EffectiveWebhookPort() int32 {
239+
if ps.Spec.WebhookPort != nil {
240+
return *ps.Spec.WebhookPort
241+
}
242+
return constants.PolicyServerListenPort
243+
}
244+
245+
// EffectiveReadinessProbePort returns the port used for the readiness probe,
246+
// using the CRD field when set or the default constant.
247+
func (ps *PolicyServer) EffectiveReadinessProbePort() int32 {
248+
if ps.Spec.ReadinessProbePort != nil {
249+
return *ps.Spec.ReadinessProbePort
250+
}
251+
return constants.PolicyServerReadinessProbePort
252+
}
253+
254+
// EffectiveMetricsPort returns the port used to expose the metrics endpoint.
255+
// It returns the CRD-level override when set, otherwise it falls back to defaultPort
256+
// (which is typically the controller-wide default configured via environment variable).
257+
func (ps *PolicyServer) EffectiveMetricsPort(defaultPort int32) int32 {
258+
if ps.Spec.MetricsPort != nil {
259+
return *ps.Spec.MetricsPort
260+
}
261+
return defaultPort
262+
}
263+
214264
// CommonLabels returns the common labels to be used with the resources
215265
// associated to a Policy Server. The labels defined follow
216266
// Kubernetes guidelines: https://kubernetes.io/docs/concepts/overview/working-with-objects/common-labels/#labels

api/policies/v1/policyserver_webhook.go

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@ import (
3636
)
3737

3838
// SetupWebhookWithManager registers the PolicyServer webhook with the controller manager.
39-
func (ps *PolicyServer) SetupWebhookWithManager(mgr ctrl.Manager, deploymentsNamespace string) error {
39+
// defaultMetricsPort is the controller-wide default metrics port (possibly overridden via env
40+
// var) and is used by the validator to detect port conflicts involving the metrics port.
41+
func (ps *PolicyServer) SetupWebhookWithManager(mgr ctrl.Manager, deploymentsNamespace string, defaultMetricsPort int32) error {
4042
logger := mgr.GetLogger().WithName("policyserver-webhook")
4143

4244
err := ctrl.NewWebhookManagedBy(mgr, ps).
@@ -45,6 +47,7 @@ func (ps *PolicyServer) SetupWebhookWithManager(mgr ctrl.Manager, deploymentsNam
4547
}).
4648
WithValidator(&policyServerValidator{
4749
deploymentsNamespace: deploymentsNamespace,
50+
defaultMetricsPort: defaultMetricsPort,
4851
k8sClient: mgr.GetClient(),
4952
logger: logger,
5053
}).
@@ -79,8 +82,12 @@ func (d *policyServerDefaulter) Default(_ context.Context, policyServer *PolicyS
7982
// polyServerCustomValidator validates PolicyServers when they are created, updated, or deleted.
8083
type policyServerValidator struct {
8184
deploymentsNamespace string
82-
k8sClient client.Client
83-
logger logr.Logger
85+
// defaultMetricsPort is the controller-wide default for the PolicyServer metrics port,
86+
// which may be overridden via the KUBEWARDEN_POLICY_SERVER_SERVICES_METRICS_PORT env var.
87+
// It is used when spec.metricsPort is not explicitly set on a PolicyServer.
88+
defaultMetricsPort int32
89+
k8sClient client.Client
90+
logger logr.Logger
8491
}
8592

8693
// ValidateCreate implements webhook.CustomValidator so a webhook will be registered for the type.
@@ -131,6 +138,7 @@ func (v *policyServerValidator) validate(ctx context.Context, policyServer *Poli
131138
}
132139

133140
allErrs = append(allErrs, validateLimitsAndRequests(policyServer.Spec.Limits, policyServer.Spec.Requests)...)
141+
allErrs = append(allErrs, v.validatePorts(policyServer)...)
134142

135143
if len(allErrs) == 0 {
136144
return nil
@@ -208,3 +216,39 @@ func validateLimitsAndRequests(limits, requests corev1.ResourceList) field.Error
208216

209217
return allErrs
210218
}
219+
220+
// validatePorts checks that the port fields in the PolicyServer spec do not
221+
// conflict with each other. Effective ports (field value or controller-configured default)
222+
// are compared so that partial overrides are also caught. The validator's defaultMetricsPort
223+
// is used so that the env-var-configured controller default is taken into account.
224+
func (v *policyServerValidator) validatePorts(policyServer *PolicyServer) field.ErrorList {
225+
var allErrs field.ErrorList
226+
227+
webhookPort := policyServer.EffectiveWebhookPort()
228+
readinessPort := policyServer.EffectiveReadinessProbePort()
229+
metricsPort := policyServer.EffectiveMetricsPort(v.defaultMetricsPort)
230+
231+
if webhookPort == readinessPort {
232+
allErrs = append(allErrs, field.Invalid(
233+
field.NewPath("spec").Child("readinessProbePort"),
234+
readinessPort,
235+
fmt.Sprintf("readinessProbePort must differ from webhookPort (%d)", webhookPort),
236+
))
237+
}
238+
if webhookPort == metricsPort {
239+
allErrs = append(allErrs, field.Invalid(
240+
field.NewPath("spec").Child("metricsPort"),
241+
metricsPort,
242+
fmt.Sprintf("metricsPort must differ from webhookPort (%d)", webhookPort),
243+
))
244+
}
245+
if readinessPort == metricsPort {
246+
allErrs = append(allErrs, field.Invalid(
247+
field.NewPath("spec").Child("metricsPort"),
248+
metricsPort,
249+
fmt.Sprintf("metricsPort must differ from readinessProbePort (%d)", readinessPort),
250+
))
251+
}
252+
253+
return allErrs
254+
}

api/policies/v1/policyserver_webhook_test.go

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,3 +279,104 @@ func TestPolicyServerValidateSigstoreTrustConfig(t *testing.T) {
279279
})
280280
}
281281
}
282+
283+
func TestValidatePorts(t *testing.T) {
284+
tests := []struct {
285+
name string
286+
webhookPort *int32
287+
readiness *int32
288+
metrics *int32
289+
defaultMetricsPort int32
290+
errContains string
291+
}{
292+
{
293+
name: "all defaults, no conflict",
294+
defaultMetricsPort: constants.PolicyServerMetricsPort,
295+
errContains: "",
296+
},
297+
{
298+
name: "webhookPort equals readinessProbePort",
299+
webhookPort: ptr.To[int32](8081),
300+
readiness: ptr.To[int32](8081),
301+
defaultMetricsPort: constants.PolicyServerMetricsPort,
302+
errContains: "readinessProbePort must differ from webhookPort",
303+
},
304+
{
305+
name: "webhookPort equals metricsPort",
306+
webhookPort: ptr.To[int32](8080),
307+
metrics: ptr.To[int32](8080),
308+
defaultMetricsPort: constants.PolicyServerMetricsPort,
309+
errContains: "metricsPort must differ from webhookPort",
310+
},
311+
{
312+
name: "readinessProbePort equals metricsPort",
313+
readiness: ptr.To[int32](9000),
314+
metrics: ptr.To[int32](9000),
315+
defaultMetricsPort: constants.PolicyServerMetricsPort,
316+
errContains: "metricsPort must differ from readinessProbePort",
317+
},
318+
{
319+
name: "all three ports the same",
320+
webhookPort: ptr.To[int32](9999),
321+
readiness: ptr.To[int32](9999),
322+
metrics: ptr.To[int32](9999),
323+
defaultMetricsPort: constants.PolicyServerMetricsPort,
324+
errContains: "readinessProbePort must differ from webhookPort",
325+
},
326+
{
327+
name: "all three ports distinct custom values",
328+
webhookPort: ptr.To[int32](9443),
329+
readiness: ptr.To[int32](9081),
330+
metrics: ptr.To[int32](9080),
331+
defaultMetricsPort: constants.PolicyServerMetricsPort,
332+
errContains: "",
333+
},
334+
{
335+
// When the controller default metrics port is overridden via env var to 9090,
336+
// a PolicyServer with readinessProbePort=9090 (and no explicit metricsPort)
337+
// must be rejected because the effective metrics port is 9090.
338+
name: "readinessProbePort conflicts with env-var-configured default metrics port",
339+
readiness: ptr.To[int32](9090),
340+
defaultMetricsPort: 9090,
341+
errContains: "metricsPort must differ from readinessProbePort",
342+
},
343+
{
344+
// When the controller default metrics port is overridden via env var to 9090,
345+
// a PolicyServer with no explicit port overrides should be valid.
346+
name: "all defaults with non-standard env-var default metrics port, no conflict",
347+
defaultMetricsPort: 9090,
348+
errContains: "",
349+
},
350+
}
351+
352+
for _, test := range tests {
353+
t.Run(test.name, func(t *testing.T) {
354+
k8sClient := fake.NewClientBuilder().Build()
355+
builder := NewPolicyServerFactory()
356+
if test.webhookPort != nil {
357+
builder = builder.WithWebhookPort(*test.webhookPort)
358+
}
359+
if test.readiness != nil {
360+
builder = builder.WithReadinessProbePort(*test.readiness)
361+
}
362+
if test.metrics != nil {
363+
builder = builder.WithMetricsPort(*test.metrics)
364+
}
365+
policyServer := builder.Build()
366+
367+
validator := policyServerValidator{
368+
deploymentsNamespace: "default",
369+
defaultMetricsPort: test.defaultMetricsPort,
370+
k8sClient: k8sClient,
371+
logger: logr.Discard(),
372+
}
373+
err := validator.validate(t.Context(), policyServer)
374+
375+
if test.errContains != "" {
376+
require.ErrorContains(t, err, test.errContains)
377+
} else {
378+
require.NoError(t, err)
379+
}
380+
})
381+
}
382+
}

api/policies/v1/zz_generated.deepcopy.go

Lines changed: 30 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

charts/kubewarden-controller/templates/_helpers.tpl

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,3 +181,20 @@ are configured.
181181
- {{ .Values.auditScanner.reportCRDsKind }}
182182
{{- end -}}
183183
{{- end -}}
184+
185+
{{/*
186+
Compute the effective affinity for the controller deployment.
187+
Uses the controller-specific affinity if set, otherwise falls back to
188+
global.affinity for backward compatibility.
189+
190+
NOTE: When hostNetwork is enabled, users are responsible for setting
191+
appropriate podAntiAffinity rules to prevent host-port conflicts between
192+
controller replicas on the same node.
193+
*/}}
194+
{{- define "kubewarden-controller.effectiveAffinity" -}}
195+
{{- if .Values.affinity -}}
196+
{{- toYaml .Values.affinity -}}
197+
{{- else if .Values.global.affinity -}}
198+
{{- toYaml .Values.global.affinity -}}
199+
{{- end -}}
200+
{{- end -}}

0 commit comments

Comments
 (0)