• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

kubevirt / kubevirt / 2165bdd0-331d-41c1-b321-73bb73738f08

15 Jul 2026 09:36AM UTC coverage: 72.518% (-0.001%) from 72.519%
2165bdd0-331d-41c1-b321-73bb73738f08

push

prow

web-flow
Merge pull request #18435 from orelmisan/binding-plugin-name

Pass network binding plugin name to sidecar containers

16 of 21 new or added lines in 4 files covered. (76.19%)

75 existing lines in 3 files now uncovered.

84161 of 116056 relevant lines covered (72.52%)

622.12 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.02
/pkg/virt-controller/services/rendercontainer.go
1
package services
2

3
import (
4
        "strconv"
5
        "strings"
6

7
        k8sv1 "k8s.io/api/core/v1"
8

9
        "kubevirt.io/kubevirt/pkg/pointer"
10

11
        v1 "kubevirt.io/api/core/v1"
12

13
        "kubevirt.io/kubevirt/pkg/util"
14
        "kubevirt.io/kubevirt/pkg/virt-launcher/virtwrap/api"
15
        "kubevirt.io/kubevirt/pkg/vmitrait"
16
)
17

18
const (
19
        cacheHomeEnvVarName  = "XDG_CACHE_HOME"
20
        configHomeEnvVarName = "XDG_CONFIG_HOME"
21
        runtimeDirEnvVarName = "XDG_RUNTIME_DIR"
22
)
23

24
type ContainerSpecRenderer struct {
25
        imgPullPolicy     k8sv1.PullPolicy
26
        launcherImg       string
27
        name              string
28
        userID            int64
29
        volumeDevices     []k8sv1.VolumeDevice
30
        volumeMounts      []k8sv1.VolumeMount
31
        sharedFilesystems []string
32
        resources         k8sv1.ResourceRequirements
33
        liveninessProbe   *k8sv1.Probe
34
        readinessProbe    *k8sv1.Probe
35
        ports             []k8sv1.ContainerPort
36
        capabilities      *k8sv1.Capabilities
37
        command           []string
38
        args              []string
39
        extraEnvVars      []k8sv1.EnvVar
40
}
41

42
type Option func(*ContainerSpecRenderer)
43

44
func NewContainerSpecRenderer(containerName string, launcherImg string, imgPullPolicy k8sv1.PullPolicy, opts ...Option) *ContainerSpecRenderer {
364✔
45
        computeContainerSpec := &ContainerSpecRenderer{
364✔
46
                imgPullPolicy: imgPullPolicy,
364✔
47
                launcherImg:   launcherImg,
364✔
48
                name:          containerName,
364✔
49
        }
364✔
50
        for _, opt := range opts {
3,202✔
51
                opt(computeContainerSpec)
2,838✔
52
        }
2,838✔
53
        return computeContainerSpec
364✔
54
}
55

56
func (csr *ContainerSpecRenderer) Render() k8sv1.Container {
370✔
57
        return k8sv1.Container{
370✔
58
                Name:                     csr.name,
370✔
59
                Image:                    csr.launcherImg,
370✔
60
                ImagePullPolicy:          csr.imgPullPolicy,
370✔
61
                SecurityContext:          securityContext(csr.userID, csr.capabilities),
370✔
62
                Command:                  csr.command,
370✔
63
                VolumeDevices:            csr.volumeDevices,
370✔
64
                VolumeMounts:             csr.volumeMounts,
370✔
65
                Resources:                csr.resources,
370✔
66
                Ports:                    csr.ports,
370✔
67
                Env:                      csr.envVars(),
370✔
68
                LivenessProbe:            csr.liveninessProbe,
370✔
69
                ReadinessProbe:           csr.readinessProbe,
370✔
70
                Args:                     csr.args,
370✔
71
                TerminationMessagePolicy: k8sv1.TerminationMessageFallbackToLogsOnError,
370✔
72
        }
370✔
73
}
370✔
74

75
func (csr *ContainerSpecRenderer) envVars() []k8sv1.EnvVar {
370✔
76
        var env []k8sv1.EnvVar
370✔
77

370✔
78
        if csr.userID != 0 {
419✔
79
                env = append(env, xdgEnvironmentVariables()...)
49✔
80
        }
49✔
81

82
        if len(csr.sharedFilesystems) != 0 {
374✔
83
                env = append(env, k8sv1.EnvVar{
4✔
84
                        Name:  util.ENV_VAR_SHARED_FILESYSTEM_PATHS,
4✔
85
                        Value: strings.Join(csr.sharedFilesystems, ":"),
4✔
86
                })
4✔
87
        }
4✔
88

89
        env = append(env, csr.extraEnvVars...)
370✔
90

370✔
91
        return env
370✔
92
}
93

94
func WithNonRoot(userID int64) Option {
49✔
95
        return func(renderer *ContainerSpecRenderer) {
98✔
96
                renderer.userID = userID
49✔
97
        }
49✔
98
}
99

100
func WithCapabilities(vmi *v1.VirtualMachineInstance) Option {
330✔
101
        return func(renderer *ContainerSpecRenderer) {
660✔
102
                if renderer.capabilities == nil {
660✔
103
                        renderer.capabilities = &k8sv1.Capabilities{
330✔
104
                                Add: requiredCapabilities(vmi),
330✔
105
                        }
330✔
106
                } else {
330✔
107
                        renderer.capabilities.Add = requiredCapabilities(vmi)
×
UNCOV
108
                }
×
109
        }
110
}
111

112
func WithDropALLCapabilities() Option {
49✔
113
        return func(renderer *ContainerSpecRenderer) {
98✔
114
                if renderer.capabilities == nil {
50✔
115
                        renderer.capabilities = &k8sv1.Capabilities{
1✔
116
                                Drop: []k8sv1.Capability{"ALL"},
1✔
117
                        }
1✔
118
                } else {
49✔
119
                        renderer.capabilities.Drop = []k8sv1.Capability{"ALL"}
48✔
120
                }
48✔
121
        }
122
}
123

124
func WithNoCapabilities() Option {
6✔
125
        return func(renderer *ContainerSpecRenderer) {
12✔
126
                renderer.capabilities = &k8sv1.Capabilities{
6✔
127
                        Drop: []k8sv1.Capability{"ALL"},
6✔
128
                }
6✔
129
        }
6✔
130
}
131

132
func WithVolumeDevices(devices ...k8sv1.VolumeDevice) Option {
327✔
133
        return func(renderer *ContainerSpecRenderer) {
654✔
134
                renderer.volumeDevices = devices
327✔
135
        }
327✔
136
}
137

138
func WithVolumeMounts(mounts ...k8sv1.VolumeMount) Option {
347✔
139
        return func(renderer *ContainerSpecRenderer) {
694✔
140
                renderer.volumeMounts = mounts
347✔
141
        }
347✔
142
}
143

144
func WithSharedFilesystems(paths ...string) Option {
325✔
145
        return func(renderer *ContainerSpecRenderer) {
650✔
146
                renderer.sharedFilesystems = paths
325✔
147
        }
325✔
148
}
149

150
func WithResourceRequirements(resources k8sv1.ResourceRequirements) Option {
346✔
151
        return func(renderer *ContainerSpecRenderer) {
692✔
152
                renderer.resources = resources
346✔
153
        }
346✔
154
}
155

156
func WithPorts(vmi *v1.VirtualMachineInstance) Option {
326✔
157
        return func(renderer *ContainerSpecRenderer) {
652✔
158
                renderer.ports = containerPortsFromVMI(vmi)
326✔
159
        }
326✔
160
}
161

162
func WithCommand(command []string) Option {
364✔
163
        return func(renderer *ContainerSpecRenderer) {
728✔
164
                renderer.command = command
364✔
165
        }
364✔
166
}
167

168
func WithArgs(args []string) Option {
347✔
169
        return func(renderer *ContainerSpecRenderer) {
694✔
170
                renderer.args = args
347✔
171
        }
347✔
172
}
173

174
func WithLivelinessProbe(vmi *v1.VirtualMachineInstance) Option {
5✔
175
        return func(renderer *ContainerSpecRenderer) {
10✔
176
                v1.SetDefaults_Probe(vmi.Spec.LivenessProbe)
5✔
177
                renderer.liveninessProbe = copyProbe(vmi.Spec.LivenessProbe)
5✔
178
                updateLivenessProbe(vmi, renderer.liveninessProbe)
5✔
179
        }
5✔
180
}
181

182
func WithReadinessProbe(vmi *v1.VirtualMachineInstance) Option {
2✔
183
        return func(renderer *ContainerSpecRenderer) {
4✔
184
                v1.SetDefaults_Probe(vmi.Spec.ReadinessProbe)
2✔
185
                renderer.readinessProbe = copyProbe(vmi.Spec.ReadinessProbe)
2✔
186
                updateReadinessProbe(vmi, renderer.readinessProbe)
2✔
187
        }
2✔
188
}
189

190
func WithExtraEnvVars(envVars []k8sv1.EnvVar) Option {
15✔
191
        return func(renderer *ContainerSpecRenderer) {
30✔
192
                renderer.extraEnvVars = append(renderer.extraEnvVars, envVars...)
15✔
193
        }
15✔
194
}
195

196
func xdgEnvironmentVariables() []k8sv1.EnvVar {
49✔
197
        const varRun = "/var/run"
49✔
198
        return []k8sv1.EnvVar{
49✔
199
                {
49✔
200
                        Name:  cacheHomeEnvVarName,
49✔
201
                        Value: util.VirtPrivateDir,
49✔
202
                },
49✔
203
                {
49✔
204
                        Name:  configHomeEnvVarName,
49✔
205
                        Value: util.VirtPrivateDir,
49✔
206
                },
49✔
207
                {
49✔
208
                        Name:  runtimeDirEnvVarName,
49✔
209
                        Value: varRun,
49✔
210
                },
49✔
211
        }
49✔
212
}
49✔
213

214
func securityContext(userId int64, requiredCapabilities *k8sv1.Capabilities) *k8sv1.SecurityContext {
370✔
215
        isNonRoot := userId != 0
370✔
216
        context := &k8sv1.SecurityContext{
370✔
217
                RunAsUser:    &userId,
370✔
218
                RunAsNonRoot: &isNonRoot,
370✔
219
                Capabilities: requiredCapabilities,
370✔
220
        }
370✔
221

370✔
222
        if isNonRoot {
419✔
223
                context.RunAsGroup = &userId
49✔
224
                context.AllowPrivilegeEscalation = pointer.P(false)
49✔
225
        }
49✔
226

227
        return context
370✔
228
}
229

230
func containerPortsFromVMI(vmi *v1.VirtualMachineInstance) []k8sv1.ContainerPort {
326✔
231
        var ports []k8sv1.ContainerPort
326✔
232

326✔
233
        for _, iface := range vmi.Spec.Domain.Devices.Interfaces {
345✔
234
                if iface.Ports != nil {
23✔
235
                        for _, port := range iface.Ports {
14✔
236
                                if port.Protocol == "" {
18✔
237
                                        port.Protocol = "TCP"
8✔
238
                                }
8✔
239

240
                                ports = append(ports, k8sv1.ContainerPort{Protocol: k8sv1.Protocol(port.Protocol), Name: port.Name, ContainerPort: port.Port})
10✔
241
                        }
242
                }
243
        }
244

245
        return ports
326✔
246
}
247

248
func updateReadinessProbe(vmi *v1.VirtualMachineInstance, computeProbe *k8sv1.Probe) {
2✔
249
        if vmi.Spec.ReadinessProbe.GuestAgentPing != nil {
2✔
UNCOV
250
                wrapGuestAgentPingWithVirtProbe(vmi, computeProbe)
×
UNCOV
251
                computeProbe.InitialDelaySeconds = computeProbe.InitialDelaySeconds + LibvirtStartupDelay
×
UNCOV
252
                return
×
253
        }
×
254
        wrapExecProbeWithVirtProbe(vmi, computeProbe)
2✔
255
        computeProbe.InitialDelaySeconds = computeProbe.InitialDelaySeconds + LibvirtStartupDelay
2✔
256
}
257

258
func updateLivenessProbe(vmi *v1.VirtualMachineInstance, computeProbe *k8sv1.Probe) {
5✔
259
        if vmi.Spec.LivenessProbe.GuestAgentPing != nil {
5✔
UNCOV
260
                wrapGuestAgentPingWithVirtProbe(vmi, computeProbe)
×
UNCOV
261
                computeProbe.InitialDelaySeconds = computeProbe.InitialDelaySeconds + LibvirtStartupDelay
×
UNCOV
262
                return
×
UNCOV
263
        }
×
264
        wrapExecProbeWithVirtProbe(vmi, computeProbe)
5✔
265
        computeProbe.InitialDelaySeconds = computeProbe.InitialDelaySeconds + LibvirtStartupDelay
5✔
266
}
267

268
func wrapExecProbeWithVirtProbe(vmi *v1.VirtualMachineInstance, probe *k8sv1.Probe) {
7✔
269
        if probe == nil || probe.ProbeHandler.Exec == nil {
12✔
270
                return
5✔
271
        }
5✔
272

273
        originalCommand := probe.ProbeHandler.Exec.Command
2✔
274
        if len(originalCommand) < 1 || originalCommand[0] == "virt-probe" {
3✔
275
                return
1✔
276
        }
1✔
277

278
        wrappedCommand := []string{
1✔
279
                "virt-probe",
1✔
280
                "--domainName", api.VMINamespaceKeyFunc(vmi),
1✔
281
                "--timeoutSeconds", strconv.FormatInt(int64(probe.TimeoutSeconds), 10),
1✔
282
                "--command", originalCommand[0],
1✔
283
                "--",
1✔
284
        }
1✔
285
        wrappedCommand = append(wrappedCommand, originalCommand[1:]...)
1✔
286

1✔
287
        probe.ProbeHandler.Exec.Command = wrappedCommand
1✔
288
        // we add 1s to the pod probe to compensate for the additional steps in probing
1✔
289
        probe.TimeoutSeconds += 1
1✔
290
}
291

292
func requiredCapabilities(vmi *v1.VirtualMachineInstance) []k8sv1.Capability {
330✔
293
        // These capabilies are always required because we set them on virt-launcher binary
330✔
294
        capabilities := []k8sv1.Capability{CAP_NET_BIND_SERVICE}
330✔
295

330✔
296
        if !vmitrait.IsNonRoot(vmi) {
612✔
297
                // add a CAP_SYS_NICE capability to allow setting cpu affinity
282✔
298
                capabilities = append(capabilities, CAP_SYS_NICE)
282✔
299
        }
282✔
300

301
        return capabilities
330✔
302
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc