Skip to content

Commit ba8c7fc

Browse files
committed
feat(controller): support hostNetwork
This commit adds the support to enable host network in the Kubewarden stack. This is done by enabling a CLI flag in the controller. Once this is done, all the policy server deployments are configured to use host network as well. Furthermore, to allow user to fix port conflicts issues, 3 new fields have been added to the policy server spec. This fields allow users to define the ports to be used by the policy server deployment. Assisted-by: Github Copilot Signed-off-by: José Guilherme Vanz <jguilhermevanz@suse.com>
1 parent e9aee77 commit ba8c7fc

27 files changed

Lines changed: 984 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)