Skip to content

Commit a5d22a3

Browse files
committed
feat(controller): support hostNetwork
Assisted-by: Github Copilot Signed-off-by: José Guilherme Vanz <jguilhermevanz@suse.com>
1 parent e9aee77 commit a5d22a3

23 files changed

Lines changed: 746 additions & 78 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: 49 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,33 @@ 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+
// using the CRD field when set or the default constant.
256+
func (ps *PolicyServer) EffectiveMetricsPort() int32 {
257+
if ps.Spec.MetricsPort != nil {
258+
return *ps.Spec.MetricsPort
259+
}
260+
return constants.PolicyServerMetricsPort
261+
}
262+
214263
// CommonLabels returns the common labels to be used with the resources
215264
// associated to a Policy Server. The labels defined follow
216265
// Kubernetes guidelines: https://kubernetes.io/docs/concepts/overview/working-with-objects/common-labels/#labels

api/policies/v1/policyserver_webhook.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ func (v *policyServerValidator) validate(ctx context.Context, policyServer *Poli
131131
}
132132

133133
allErrs = append(allErrs, validateLimitsAndRequests(policyServer.Spec.Limits, policyServer.Spec.Requests)...)
134+
allErrs = append(allErrs, validatePorts(policyServer)...)
134135

135136
if len(allErrs) == 0 {
136137
return nil
@@ -208,3 +209,38 @@ func validateLimitsAndRequests(limits, requests corev1.ResourceList) field.Error
208209

209210
return allErrs
210211
}
212+
213+
// validatePorts checks that the port fields in the PolicyServer spec do not
214+
// conflict with each other. Effective ports (field value or constant default)
215+
// are compared so that partial overrides are also caught.
216+
func validatePorts(policyServer *PolicyServer) field.ErrorList {
217+
var allErrs field.ErrorList
218+
219+
webhookPort := policyServer.EffectiveWebhookPort()
220+
readinessPort := policyServer.EffectiveReadinessProbePort()
221+
metricsPort := policyServer.EffectiveMetricsPort()
222+
223+
if webhookPort == readinessPort {
224+
allErrs = append(allErrs, field.Invalid(
225+
field.NewPath("spec").Child("readinessProbePort"),
226+
readinessPort,
227+
fmt.Sprintf("readinessProbePort must differ from webhookPort (%d)", webhookPort),
228+
))
229+
}
230+
if webhookPort == metricsPort {
231+
allErrs = append(allErrs, field.Invalid(
232+
field.NewPath("spec").Child("metricsPort"),
233+
metricsPort,
234+
fmt.Sprintf("metricsPort must differ from webhookPort (%d)", webhookPort),
235+
))
236+
}
237+
if readinessPort == metricsPort {
238+
allErrs = append(allErrs, field.Invalid(
239+
field.NewPath("spec").Child("metricsPort"),
240+
metricsPort,
241+
fmt.Sprintf("metricsPort must differ from readinessProbePort (%d)", readinessPort),
242+
))
243+
}
244+
245+
return allErrs
246+
}

api/policies/v1/policyserver_webhook_test.go

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,3 +279,80 @@ 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+
errContains string
290+
}{
291+
{
292+
name: "all defaults, no conflict",
293+
errContains: "",
294+
},
295+
{
296+
name: "webhookPort equals readinessProbePort",
297+
webhookPort: ptr.To[int32](8081),
298+
readiness: ptr.To[int32](8081),
299+
errContains: "readinessProbePort must differ from webhookPort",
300+
},
301+
{
302+
name: "webhookPort equals metricsPort",
303+
webhookPort: ptr.To[int32](8080),
304+
metrics: ptr.To[int32](8080),
305+
errContains: "metricsPort must differ from webhookPort",
306+
},
307+
{
308+
name: "readinessProbePort equals metricsPort",
309+
readiness: ptr.To[int32](9000),
310+
metrics: ptr.To[int32](9000),
311+
errContains: "metricsPort must differ from readinessProbePort",
312+
},
313+
{
314+
name: "all three ports the same",
315+
webhookPort: ptr.To[int32](9999),
316+
readiness: ptr.To[int32](9999),
317+
metrics: ptr.To[int32](9999),
318+
errContains: "readinessProbePort must differ from webhookPort",
319+
},
320+
{
321+
name: "all three ports distinct custom values",
322+
webhookPort: ptr.To[int32](9443),
323+
readiness: ptr.To[int32](9081),
324+
metrics: ptr.To[int32](9080),
325+
errContains: "",
326+
},
327+
}
328+
329+
for _, test := range tests {
330+
t.Run(test.name, func(t *testing.T) {
331+
k8sClient := fake.NewClientBuilder().Build()
332+
builder := NewPolicyServerFactory()
333+
if test.webhookPort != nil {
334+
builder = builder.WithWebhookPort(*test.webhookPort)
335+
}
336+
if test.readiness != nil {
337+
builder = builder.WithReadinessProbePort(*test.readiness)
338+
}
339+
if test.metrics != nil {
340+
builder = builder.WithMetricsPort(*test.metrics)
341+
}
342+
policyServer := builder.Build()
343+
344+
validator := policyServerValidator{
345+
deploymentsNamespace: "default",
346+
k8sClient: k8sClient,
347+
logger: logr.Discard(),
348+
}
349+
err := validator.validate(t.Context(), policyServer)
350+
351+
if test.errContains != "" {
352+
require.ErrorContains(t, err, test.errContains)
353+
} else {
354+
require.NoError(t, err)
355+
}
356+
})
357+
}
358+
}

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 -}}

charts/kubewarden-controller/templates/deployment.yaml

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,9 @@ spec:
3232
{{- include "imagePullSecrets" .Values.imagePullSecrets | nindent 8 }}
3333
{{- end }}
3434
serviceAccountName: {{ include "kubewarden-controller.serviceAccountName" . }}
35-
{{- if .Values.global.affinity }}
36-
affinity: {{ .Values.global.affinity | toYaml | nindent 8 }}
35+
{{- $effectiveAffinity := include "kubewarden-controller.effectiveAffinity" . }}
36+
{{- if $effectiveAffinity }}
37+
affinity: {{ $effectiveAffinity | nindent 8 }}
3738
{{- end }}
3839
{{- if .Values.global.tolerations }}
3940
tolerations: {{ .Values.global.tolerations | toYaml | nindent 8 }}
@@ -45,12 +46,19 @@ spec:
4546
{{- if .Values.global.priorityClassName }}
4647
priorityClassName: {{ .Values.global.priorityClassName | toYaml | nindent 8 }}
4748
{{- end }}
49+
{{- if .Values.hostNetwork }}
50+
hostNetwork: true
51+
dnsPolicy: ClusterFirstWithHostNet
52+
{{- end }}
4853
containers:
4954
- name: controller
5055
args:
5156
- --leader-elect
5257
- --deployments-namespace={{ .Release.Namespace }}
5358
- --webhook-service-name={{ include "kubewarden-controller.fullname" . }}-webhook-service
59+
- --webhook-server-port={{ .Values.ports.webhook }}
60+
- --health-probe-bind-address=:{{ .Values.ports.healthProbe }}
61+
- --metrics-bind-address=:{{ .Values.ports.metrics }}
5462
{{- if .Values.alwaysAcceptAdmissionReviewsOnDeploymentsNamespace }}
5563
- --always-accept-admission-reviews-on-deployments-namespace
5664
{{- end }}
@@ -62,6 +70,9 @@ spec:
6270
{{- if $imagePullSecretNames }}
6371
- --image-pull-secrets={{ $imagePullSecretNames }}
6472
{{- end }}
73+
{{- if .Values.hostNetwork }}
74+
- --host-network
75+
{{- end }}
6576
{{- if or .Values.telemetry.metrics .Values.telemetry.tracing }}
6677
{{- if eq .Values.telemetry.mode "sidecar" }}
6778
- --enable-otel-sidecar
@@ -117,13 +128,13 @@ spec:
117128
livenessProbe:
118129
httpGet:
119130
path: /healthz
120-
port: 8081
131+
port: {{ .Values.ports.healthProbe }}
121132
initialDelaySeconds: 15
122133
periodSeconds: 20
123134
readinessProbe:
124135
httpGet:
125136
path: /readyz
126-
port: 8081
137+
port: {{ .Values.ports.healthProbe }}
127138
initialDelaySeconds: 5
128139
periodSeconds: 10
129140
{{- if and .Values.resources .Values.resources.controller }}
@@ -154,7 +165,7 @@ spec:
154165
readOnly: true
155166
{{- end }}
156167
ports:
157-
- containerPort: 9443
168+
- containerPort: {{ .Values.ports.webhook }}
158169
name: webhook-server
159170
protocol: TCP
160171
volumes:

charts/kubewarden-controller/templates/service.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@ spec:
1313
{{- if .Values.telemetry.metrics }}
1414
- name: metrics
1515
port: 8080
16-
targetPort: 8080
16+
targetPort: {{ .Values.ports.metrics }}
1717
{{- end}}
1818
- name: https
1919
port: 8443
20-
targetPort: https
20+
targetPort: {{ .Values.ports.webhook }}
2121
selector:
2222
{{- include "kubewarden-controller.selectorLabels" . | nindent 4 }}
2323
---
@@ -33,6 +33,6 @@ metadata:
3333
spec:
3434
ports:
3535
- port: 443
36-
targetPort: 9443
36+
targetPort: {{ .Values.ports.webhook }}
3737
selector:
3838
{{- include "kubewarden-controller.selectorLabels" . | nindent 4 }}

0 commit comments

Comments
 (0)