Skip to content

Commit 6a442c6

Browse files
committed
Add kernel parameter reporting to hypervisor status
This enables the operator to report kernel boot parameters in the Hypervisor status, allowing users to verify kernel configuration across the fleet.
1 parent a01b62e commit 6a442c6

8 files changed

Lines changed: 367 additions & 46 deletions

File tree

config/crd/bases/kvm.cloud.sap_hypervisors.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,10 @@ spec:
459459
hardwareVendor:
460460
description: HardwareVendor
461461
type: string
462+
kernelCommandLine:
463+
description: KernelCommandLine contains the raw kernel boot
464+
parameters from /proc/cmdline.
465+
type: string
462466
kernelName:
463467
description: KernelName
464468
type: string

go.mod

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,18 @@ go 1.25.0
77

88
require (
99
github.com/cert-manager/cert-manager v1.19.3
10-
github.com/cobaltcore-dev/openstack-hypervisor-operator v0.0.0-20260107080351-e998a1af4394
10+
github.com/cobaltcore-dev/openstack-hypervisor-operator v0.0.0-20260220122208-77e78a97ad93
1111
github.com/coreos/go-systemd/v22 v22.6.0
1212
github.com/digitalocean/go-libvirt v0.0.0-20260105165635-a0e369cfdc9f
1313
github.com/godbus/dbus/v5 v5.2.2
14-
github.com/onsi/ginkgo/v2 v2.27.3
15-
github.com/onsi/gomega v1.38.3
14+
github.com/onsi/ginkgo/v2 v2.28.1
15+
github.com/onsi/gomega v1.39.1
1616
github.com/sapcc/go-api-declarations v1.18.0
17+
github.com/stretchr/testify v1.11.1
1718
k8s.io/api v0.35.0
1819
k8s.io/apimachinery v0.35.0
1920
k8s.io/client-go v0.35.0
20-
sigs.k8s.io/controller-runtime v0.22.4
21+
sigs.k8s.io/controller-runtime v0.23.1
2122
)
2223

2324
require (
@@ -56,7 +57,7 @@ require (
5657
github.com/google/cel-go v0.26.1 // indirect
5758
github.com/google/gnostic-models v0.7.1 // indirect
5859
github.com/google/go-cmp v0.7.0 // indirect
59-
github.com/google/pprof v0.0.0-20251007162407-5df77e3f7d1d // indirect
60+
github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83 // indirect
6061
github.com/google/uuid v1.6.0 // indirect
6162
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.4 // indirect
6263
github.com/inconshreveable/mousetrap v1.1.0 // indirect
@@ -86,24 +87,25 @@ require (
8687
go.uber.org/zap v1.27.1 // indirect
8788
go.yaml.in/yaml/v2 v2.4.3 // indirect
8889
go.yaml.in/yaml/v3 v3.0.4 // indirect
89-
golang.org/x/crypto v0.46.0 // indirect
90+
golang.org/x/crypto v0.47.0 // indirect
9091
golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 // indirect
91-
golang.org/x/mod v0.31.0 // indirect
92-
golang.org/x/net v0.48.0 // indirect
92+
golang.org/x/mod v0.32.0 // indirect
93+
golang.org/x/net v0.49.0 // indirect
9394
golang.org/x/oauth2 v0.34.0 // indirect
9495
golang.org/x/sync v0.19.0 // indirect
95-
golang.org/x/sys v0.39.0 // indirect
96-
golang.org/x/term v0.38.0 // indirect
97-
golang.org/x/text v0.32.0 // indirect
96+
golang.org/x/sys v0.40.0 // indirect
97+
golang.org/x/term v0.39.0 // indirect
98+
golang.org/x/text v0.33.0 // indirect
9899
golang.org/x/time v0.14.0 // indirect
99-
golang.org/x/tools v0.40.0 // indirect
100+
golang.org/x/tools v0.41.0 // indirect
100101
gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect
101102
google.golang.org/genproto/googleapis/api v0.0.0-20251222181119-0a764e51fe1b // indirect
102103
google.golang.org/genproto/googleapis/rpc v0.0.0-20251222181119-0a764e51fe1b // indirect
103104
google.golang.org/grpc v1.78.0 // indirect
104105
google.golang.org/protobuf v1.36.11 // indirect
105106
gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect
106107
gopkg.in/inf.v0 v0.9.1 // indirect
108+
gopkg.in/yaml.v3 v3.0.1 // indirect
107109
k8s.io/apiextensions-apiserver v0.35.0 // indirect
108110
k8s.io/apiserver v0.35.0 // indirect
109111
k8s.io/component-base v0.35.0 // indirect
@@ -114,6 +116,6 @@ require (
114116
sigs.k8s.io/gateway-api v1.4.1 // indirect
115117
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect
116118
sigs.k8s.io/randfill v1.0.0 // indirect
117-
sigs.k8s.io/structured-merge-diff/v6 v6.3.1 // indirect
119+
sigs.k8s.io/structured-merge-diff/v6 v6.3.2 // indirect
118120
sigs.k8s.io/yaml v1.6.0 // indirect
119121
)

go.sum

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ github.com/cert-manager/cert-manager v1.19.3 h1:3d0Nk/HO3BOmAdBJNaBh+6YgaO3Ciey3
1414
github.com/cert-manager/cert-manager v1.19.3/go.mod h1:e9NzLtOKxTw7y99qLyWGmPo6mrC1Nh0EKKcMkRfK+GE=
1515
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
1616
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
17-
github.com/cobaltcore-dev/openstack-hypervisor-operator v0.0.0-20260107080351-e998a1af4394 h1:GWyHLNTwXp4m+D7OGuQwtIWGRPUBCEjVSowK4CgrdQU=
18-
github.com/cobaltcore-dev/openstack-hypervisor-operator v0.0.0-20260107080351-e998a1af4394/go.mod h1:i/YQm59sAvilkgTFpKc+elMIf/KzkdimnXMd13P3V9s=
17+
github.com/cobaltcore-dev/openstack-hypervisor-operator v0.0.0-20260220122208-77e78a97ad93 h1:26yzG6yaWqH1+rzylAs70M+5j8u7xefj5sZUh9inKKA=
18+
github.com/cobaltcore-dev/openstack-hypervisor-operator v0.0.0-20260220122208-77e78a97ad93/go.mod h1:zeuojfPLm8ZLhBhWAmDpONNRVArbhCcFZpdsl4+fdY0=
1919
github.com/coreos/go-systemd/v22 v22.6.0 h1:aGVa/v8B7hpb0TKl0MWoAavPDmHvobFe5R5zn0bCJWo=
2020
github.com/coreos/go-systemd/v22 v22.6.0/go.mod h1:iG+pp635Fo7ZmV/j14KUcmEyWF+0X7Lua8rrTWzYgWU=
2121
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
@@ -103,8 +103,8 @@ github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX
103103
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
104104
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
105105
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
106-
github.com/google/pprof v0.0.0-20251007162407-5df77e3f7d1d h1:KJIErDwbSHjnp/SGzE5ed8Aol7JsKiI5X7yWKAtzhM0=
107-
github.com/google/pprof v0.0.0-20251007162407-5df77e3f7d1d/go.mod h1:I6V7YzU0XDpsHqbsyrghnFZLO1gwK6NPTNvmetQIk9U=
106+
github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83 h1:z2ogiKUYzX5Is6zr/vP9vJGqPwcdqsWjOt+V8J7+bTc=
107+
github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83/go.mod h1:MxpfABSjhmINe3F1It9d+8exIHFvUqtLIRCdOGNXqiI=
108108
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
109109
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
110110
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.4 h1:kEISI/Gx67NzH3nJxAmY/dGac80kKZgZt134u7Y/k1s=
@@ -135,10 +135,10 @@ github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFd
135135
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
136136
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
137137
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
138-
github.com/onsi/ginkgo/v2 v2.27.3 h1:ICsZJ8JoYafeXFFlFAG75a7CxMsJHwgKwtO+82SE9L8=
139-
github.com/onsi/ginkgo/v2 v2.27.3/go.mod h1:ArE1D/XhNXBXCBkKOLkbsb2c81dQHCRcF5zwn/ykDRo=
140-
github.com/onsi/gomega v1.38.3 h1:eTX+W6dobAYfFeGC2PV6RwXRu/MyT+cQguijutvkpSM=
141-
github.com/onsi/gomega v1.38.3/go.mod h1:ZCU1pkQcXDO5Sl9/VVEGlDyp+zm0m1cmeG5TOzLgdh4=
138+
github.com/onsi/ginkgo/v2 v2.28.1 h1:S4hj+HbZp40fNKuLUQOYLDgZLwNUVn19N3Atb98NCyI=
139+
github.com/onsi/ginkgo/v2 v2.28.1/go.mod h1:CLtbVInNckU3/+gC8LzkGUb9oF+e8W8TdUsxPwvdOgE=
140+
github.com/onsi/gomega v1.39.1 h1:1IJLAad4zjPn2PsnhH70V4DKRFlrCzGBNrNaru+Vf28=
141+
github.com/onsi/gomega v1.39.1/go.mod h1:hL6yVALoTOxeWudERyfppUcZXjMwIMLnuSfruD2lcfg=
142142
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
143143
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
144144
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
@@ -215,28 +215,28 @@ go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0=
215215
go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8=
216216
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
217217
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
218-
golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
219-
golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
218+
golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8=
219+
golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A=
220220
golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 h1:fQsdNF2N+/YewlRZiricy4P1iimyPKZ/xwniHj8Q2a0=
221221
golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93/go.mod h1:EPRbTFwzwjXj9NpYyyrvenVh9Y+GFeEvMNh7Xuz7xgU=
222-
golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI=
223-
golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg=
224-
golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU=
225-
golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY=
222+
golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c=
223+
golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU=
224+
golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o=
225+
golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8=
226226
golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw=
227227
golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
228228
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
229229
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
230-
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
231-
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
232-
golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q=
233-
golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg=
234-
golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
235-
golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
230+
golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ=
231+
golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
232+
golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY=
233+
golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww=
234+
golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE=
235+
golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8=
236236
golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
237237
golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
238-
golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA=
239-
golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc=
238+
golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc=
239+
golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg=
240240
gomodules.xyz/jsonpatch/v2 v2.5.0 h1:JELs8RLM12qJGXU4u/TO3V25KW8GreMKl9pdkk14RM0=
241241
gomodules.xyz/jsonpatch/v2 v2.5.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
242242
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
@@ -279,15 +279,15 @@ k8s.io/utils v0.0.0-20251222233032-718f0e51e6d2 h1:OfgiEo21hGiwx1oJUU5MpEaeOEg6c
279279
k8s.io/utils v0.0.0-20251222233032-718f0e51e6d2/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk=
280280
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.34.0 h1:hSfpvjjTQXQY2Fol2CS0QHMNs/WI1MOSGzCm1KhM5ec=
281281
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.34.0/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw=
282-
sigs.k8s.io/controller-runtime v0.22.4 h1:GEjV7KV3TY8e+tJ2LCTxUTanW4z/FmNB7l327UfMq9A=
283-
sigs.k8s.io/controller-runtime v0.22.4/go.mod h1:+QX1XUpTXN4mLoblf4tqr5CQcyHPAki2HLXqQMY6vh8=
282+
sigs.k8s.io/controller-runtime v0.23.1 h1:TjJSM80Nf43Mg21+RCy3J70aj/W6KyvDtOlpKf+PupE=
283+
sigs.k8s.io/controller-runtime v0.23.1/go.mod h1:B6COOxKptp+YaUT5q4l6LqUJTRpizbgf9KSRNdQGns0=
284284
sigs.k8s.io/gateway-api v1.4.1 h1:NPxFutNkKNa8UfLd2CMlEuhIPMQgDQ6DXNKG9sHbJU8=
285285
sigs.k8s.io/gateway-api v1.4.1/go.mod h1:AR5RSqciWP98OPckEjOjh2XJhAe2Na4LHyXD2FUY7Qk=
286286
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg=
287287
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=
288288
sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=
289289
sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
290-
sigs.k8s.io/structured-merge-diff/v6 v6.3.1 h1:JrhdFMqOd/+3ByqlP2I45kTOZmTRLBUm5pvRjeheg7E=
291-
sigs.k8s.io/structured-merge-diff/v6 v6.3.1/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE=
290+
sigs.k8s.io/structured-merge-diff/v6 v6.3.2 h1:kwVWMx5yS1CrnFWA/2QHyRVJ8jM6dBA80uLmm0wJkk8=
291+
sigs.k8s.io/structured-merge-diff/v6 v6.3.2/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE=
292292
sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs=
293293
sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4=

internal/controller/hypervisor_controller.go

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import (
3838

3939
"github.com/cobaltcore-dev/kvm-node-agent/internal/certificates"
4040
"github.com/cobaltcore-dev/kvm-node-agent/internal/evacuation"
41+
"github.com/cobaltcore-dev/kvm-node-agent/internal/kernel"
4142
"github.com/cobaltcore-dev/kvm-node-agent/internal/libvirt"
4243
"github.com/cobaltcore-dev/kvm-node-agent/internal/sys"
4344
"github.com/cobaltcore-dev/kvm-node-agent/internal/systemd"
@@ -46,11 +47,13 @@ import (
4647
// HypervisorReconciler reconciles a Hypervisor object
4748
type HypervisorReconciler struct {
4849
client.Client
49-
Scheme *runtime.Scheme
50-
Systemd systemd.Interface
51-
Libvirt libvirt.Interface
50+
Scheme *runtime.Scheme
51+
Systemd systemd.Interface
52+
Libvirt libvirt.Interface
53+
KernelReader kernel.Interface
5254

5355
osDescriptor *systemd.Descriptor
56+
kernelParameters *kernel.Parameters
5457
evacuateOnReboot bool
5558

5659
// Channel that can be used to trigger reconcile events.
@@ -149,6 +152,11 @@ func (r *HypervisorReconciler) Reconcile(ctx context.Context, req ctrl.Request)
149152
hypervisor.Status.OperatingSystem.FirmwareDate = metav1.NewTime(time.UnixMicro(r.osDescriptor.FirmwareDate))
150153
}
151154

155+
if r.kernelParameters != nil &&
156+
hypervisor.Status.OperatingSystem.KernelCommandLine == "" {
157+
hypervisor.Status.OperatingSystem.KernelCommandLine = r.kernelParameters.CommandLine
158+
}
159+
152160
if hypervisor.Spec.EvacuateOnReboot != r.evacuateOnReboot {
153161
if hypervisor.Spec.EvacuateOnReboot {
154162
e := &evacuation.EvictionController{Client: r.Client}
@@ -360,6 +368,13 @@ func (r *HypervisorReconciler) SetupWithManager(mgr ctrl.Manager) error {
360368
return fmt.Errorf("unable to get Systemd hostname describe(): %w", err)
361369
}
362370

371+
if r.KernelReader == nil {
372+
r.KernelReader = kernel.NewSystemReader()
373+
}
374+
if r.kernelParameters, err = r.KernelReader.ReadParameters(); err != nil {
375+
return fmt.Errorf("unable to read kernel parameters: %w", err)
376+
}
377+
363378
// Prepare an event channel that will trigger a reconcile event.
364379
r.reconcileCh = make(chan event.GenericEvent)
365380
src := source.Channel(r.reconcileCh, &handler.EnqueueRequestForObject{})

internal/controller/hypervisor_controller_test.go

Lines changed: 69 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import (
3535
"sigs.k8s.io/controller-runtime/pkg/event"
3636
"sigs.k8s.io/controller-runtime/pkg/reconcile"
3737

38+
"github.com/cobaltcore-dev/kvm-node-agent/internal/kernel"
3839
"github.com/cobaltcore-dev/kvm-node-agent/internal/libvirt"
3940
"github.com/cobaltcore-dev/kvm-node-agent/internal/sys"
4041
"github.com/cobaltcore-dev/kvm-node-agent/internal/systemd"
@@ -127,13 +128,22 @@ var _ = Describe("Hypervisor Controller", func() {
127128
})
128129

129130
Context("When testing SetupWithManager method", func() {
130-
It("should successfully setup controller with manager", func() {
131+
It("should successfully setup controller with manager and read kernel parameters", func() {
131132
// Create a test manager
132133
mgr, err := ctrl.NewManager(cfg, ctrl.Options{
133134
Scheme: k8sClient.Scheme(),
134135
})
135136
Expect(err).NotTo(HaveOccurred())
136137

138+
// Use mock kernel reader
139+
mockKernelReader := &kernel.InterfaceMock{
140+
ReadParametersFunc: func() (*kernel.Parameters, error) {
141+
return &kernel.Parameters{
142+
CommandLine: "quiet splash console=ttyS0 intel_iommu=on",
143+
}, nil
144+
},
145+
}
146+
137147
controllerReconciler := &HypervisorReconciler{
138148
Client: k8sClient,
139149
Scheme: k8sClient.Scheme(),
@@ -156,13 +166,21 @@ var _ = Describe("Hypervisor Controller", func() {
156166
}, nil
157167
},
158168
},
169+
KernelReader: mockKernelReader,
159170
}
160171

161172
err = controllerReconciler.SetupWithManager(mgr)
162173
Expect(err).NotTo(HaveOccurred())
163174
Expect(controllerReconciler.reconcileCh).NotTo(BeNil())
164175
Expect(controllerReconciler.osDescriptor).NotTo(BeNil())
165176
Expect(controllerReconciler.osDescriptor.OperatingSystemReleaseData).To(HaveLen(2))
177+
178+
// Verify that kernel reader was called and parameters were stored
179+
Expect(mockKernelReader.ReadParametersCalls()).To(HaveLen(1))
180+
Expect(controllerReconciler.kernelParameters).NotTo(BeNil())
181+
Expect(
182+
controllerReconciler.kernelParameters.CommandLine,
183+
).To(Equal("quiet splash console=ttyS0 intel_iommu=on"))
166184
})
167185

168186
It("should fail when systemd Describe returns error", func() {
@@ -172,9 +190,16 @@ var _ = Describe("Hypervisor Controller", func() {
172190
})
173191
Expect(err).NotTo(HaveOccurred())
174192

193+
mockKernelReader := &kernel.InterfaceMock{
194+
ReadParametersFunc: func() (*kernel.Parameters, error) {
195+
return &kernel.Parameters{CommandLine: "quiet splash"}, nil
196+
},
197+
}
198+
175199
controllerReconciler := &HypervisorReconciler{
176-
Client: k8sClient,
177-
Scheme: k8sClient.Scheme(),
200+
Client: k8sClient,
201+
Scheme: k8sClient.Scheme(),
202+
KernelReader: mockKernelReader,
178203
Systemd: &systemd.InterfaceMock{
179204
DescribeFunc: func(ctx context.Context) (*systemd.Descriptor, error) {
180205
return nil, errors.New("systemd describe failed")
@@ -187,6 +212,39 @@ var _ = Describe("Hypervisor Controller", func() {
187212
Expect(err.Error()).To(ContainSubstring("unable to get Systemd hostname describe()"))
188213
Expect(err.Error()).To(ContainSubstring("systemd describe failed"))
189214
})
215+
216+
It("should fail when kernel parameters cannot be read", func() {
217+
// Create a test manager
218+
mgr, err := ctrl.NewManager(cfg, ctrl.Options{
219+
Scheme: k8sClient.Scheme(),
220+
})
221+
Expect(err).NotTo(HaveOccurred())
222+
223+
mockKernelReader := &kernel.InterfaceMock{
224+
ReadParametersFunc: func() (*kernel.Parameters, error) {
225+
return nil, errors.New("failed to read /proc/cmdline")
226+
},
227+
}
228+
229+
controllerReconciler := &HypervisorReconciler{
230+
Client: k8sClient,
231+
Scheme: k8sClient.Scheme(),
232+
KernelReader: mockKernelReader,
233+
Systemd: &systemd.InterfaceMock{
234+
DescribeFunc: func(ctx context.Context) (*systemd.Descriptor, error) {
235+
return &systemd.Descriptor{
236+
KernelVersion: "6.1.0",
237+
}, nil
238+
},
239+
},
240+
}
241+
242+
err = controllerReconciler.SetupWithManager(mgr)
243+
Expect(err).To(HaveOccurred())
244+
Expect(err.Error()).To(ContainSubstring("unable to read kernel parameters"))
245+
Expect(err.Error()).To(ContainSubstring("failed to read /proc/cmdline"))
246+
Expect(mockKernelReader.ReadParametersCalls()).To(HaveLen(1))
247+
})
190248
})
191249

192250
Context("When reconciling a resource", func() {
@@ -227,8 +285,9 @@ var _ = Describe("Hypervisor Controller", func() {
227285
By("Cleanup the specific resource instance Hypervisor")
228286
Expect(k8sClient.Delete(ctx, resource)).To(Succeed())
229287
})
230-
It("should successfully reconcile the resource", func() {
288+
It("should successfully reconcile the resource with kernel parameters", func() {
231289
By("Reconciling the created resource")
290+
232291
controllerReconciler := &HypervisorReconciler{
233292
Client: k8sClient,
234293
Scheme: k8sClient.Scheme(),
@@ -289,6 +348,9 @@ var _ = Describe("Hypervisor Controller", func() {
289348
"VARIANT_ID=metal-sci_usi-amd64",
290349
},
291350
},
351+
kernelParameters: &kernel.Parameters{
352+
CommandLine: "quiet splash console=ttyS0 intel_iommu=on",
353+
},
292354
}
293355

294356
_, err := controllerReconciler.Reconcile(ctx, reconcile.Request{
@@ -321,6 +383,9 @@ var _ = Describe("Hypervisor Controller", func() {
321383
Expect(hypervisor.Status.OperatingSystem.GardenLinuxCommitID).To(Equal("abcdef1234567890"))
322384
Expect(hypervisor.Status.OperatingSystem.GardenLinuxFeatures).To(Equal([]string{"_rescue", "log", "sap"}))
323385
Expect(hypervisor.Status.OperatingSystem.VariantID).To(Equal("metal-sci_usi-amd64"))
386+
Expect(
387+
hypervisor.Status.OperatingSystem.KernelCommandLine,
388+
).To(Equal("quiet splash console=ttyS0 intel_iommu=on"))
324389
})
325390
})
326391
})

0 commit comments

Comments
 (0)