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

kubevirt / kubevirt / 1f279da4-80f1-4827-a9a3-06d287529bae

21 Dec 2025 01:07PM UTC coverage: 70.643% (-0.006%) from 70.649%
1f279da4-80f1-4827-a9a3-06d287529bae

push

prow

web-flow
Merge pull request #16285 from ShellyKa13/vmbackup-incremental

VMBackup: support incremental backup

257 of 353 new or added lines in 15 files covered. (72.8%)

8 existing lines in 5 files now uncovered.

71790 of 101623 relevant lines covered (70.64%)

412.81 hits per line

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

66.1
/pkg/virt-api/api.go
1
/*
2
 * This file is part of the KubeVirt project
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 *
16
 * Copyright The KubeVirt Authors.
17
 *
18
 */
19

20
package virt_api
21

22
import (
23
        "context"
24
        "crypto/tls"
25
        "encoding/json"
26
        "fmt"
27
        "net/http"
28
        "os"
29
        "os/signal"
30
        "sync"
31
        "syscall"
32
        "time"
33

34
        builderv3 "k8s.io/kube-openapi/pkg/builder3"
35
        "k8s.io/kube-openapi/pkg/common/restfuladapter"
36
        "k8s.io/kube-openapi/pkg/validation/spec"
37

38
        kvtls "kubevirt.io/kubevirt/pkg/util/tls"
39

40
        restful "github.com/emicklei/go-restful/v3"
41
        "github.com/prometheus/client_golang/prometheus/promhttp"
42
        flag "github.com/spf13/pflag"
43
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
44
        "k8s.io/apimachinery/pkg/runtime/schema"
45
        "k8s.io/apimachinery/pkg/util/validation/field"
46
        "k8s.io/client-go/tools/cache"
47
        certificate2 "k8s.io/client-go/util/certificate"
48
        "k8s.io/client-go/util/flowcontrol"
49
        aggregatorclient "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset"
50

51
        "kubevirt.io/kubevirt/pkg/util/ratelimiter"
52

53
        backupv1 "kubevirt.io/api/backup/v1alpha1"
54
        v1 "kubevirt.io/api/core/v1"
55
        "kubevirt.io/client-go/kubecli"
56
        "kubevirt.io/client-go/log"
57
        clientutil "kubevirt.io/client-go/util"
58
        virtversion "kubevirt.io/client-go/version"
59

60
        v12 "kubevirt.io/client-go/api"
61

62
        "kubevirt.io/kubevirt/pkg/certificates/bootstrap"
63
        "kubevirt.io/kubevirt/pkg/controller"
64
        "kubevirt.io/kubevirt/pkg/healthz"
65
        clientmetrics "kubevirt.io/kubevirt/pkg/monitoring/metrics/common/client"
66
        metrics "kubevirt.io/kubevirt/pkg/monitoring/metrics/virt-api"
67
        "kubevirt.io/kubevirt/pkg/monitoring/profiler"
68
        netadmitter "kubevirt.io/kubevirt/pkg/network/admitter"
69
        mime "kubevirt.io/kubevirt/pkg/rest"
70
        "kubevirt.io/kubevirt/pkg/rest/filter"
71
        "kubevirt.io/kubevirt/pkg/service"
72
        "kubevirt.io/kubevirt/pkg/util"
73
        "kubevirt.io/kubevirt/pkg/util/openapi"
74
        "kubevirt.io/kubevirt/pkg/virt-api/definitions"
75
        "kubevirt.io/kubevirt/pkg/virt-api/rest"
76
        "kubevirt.io/kubevirt/pkg/virt-api/webhooks"
77
        mutating_webhook "kubevirt.io/kubevirt/pkg/virt-api/webhooks/mutating-webhook"
78
        validating_webhook "kubevirt.io/kubevirt/pkg/virt-api/webhooks/validating-webhook"
79
        virtconfig "kubevirt.io/kubevirt/pkg/virt-config"
80
        "kubevirt.io/kubevirt/pkg/virt-operator/resource/generate/components"
81
        virtoperatorutils "kubevirt.io/kubevirt/pkg/virt-operator/util"
82
)
83

84
const (
85
        // Default port that virt-api listens on.
86
        defaultPort = 443
87

88
        // Default address that virt-api listens on.
89
        defaultHost = "0.0.0.0"
90

91
        DefaultConsoleServerPort = 8186
92

93
        defaultCAConfigMapName     = "kubevirt-ca"
94
        defaultTlsCertFilePath     = "/etc/virt-api/certificates/tls.crt"
95
        defaultTlsKeyFilePath      = "/etc/virt-api/certificates/tls.key"
96
        defaultHandlerCertFilePath = "/etc/virt-handler/clientcertificates/tls.crt"
97
        defaultHandlerKeyFilePath  = "/etc/virt-handler/clientcertificates/tls.key"
98

99
        httpStatusNotFoundMessage     = "Not Found"
100
        httpStatusBadRequestMessage   = "Bad Request"
101
        httpStatusInternalServerError = "Internal Server Error"
102
)
103

104
type VirtApi interface {
105
        Compose()
106
        Run()
107
        AddFlags()
108
        ConfigureOpenAPIService()
109
        Execute()
110
}
111

112
type virtAPIApp struct {
113
        service.ServiceListen
114
        SwaggerUI        string
115
        SubresourcesOnly bool
116
        virtCli          kubecli.KubevirtClient
117
        aggregatorClient *aggregatorclient.Clientset
118
        authorizor       rest.VirtApiAuthorizor
119
        certsDirectory   string
120
        clusterConfig    *virtconfig.ClusterConfig
121

122
        namespace               string
123
        host                    string
124
        tlsConfig               *tls.Config
125
        certificate             *tls.Certificate
126
        consoleServerPort       int
127
        certmanager             certificate2.Manager
128
        handlerTLSConfiguration *tls.Config
129
        handlerCertManager      certificate2.Manager
130

131
        caConfigMapName              string
132
        tlsCertFilePath              string
133
        tlsKeyFilePath               string
134
        handlerCertFilePath          string
135
        handlerKeyFilePath           string
136
        externallyManaged            bool
137
        reloadableRateLimiter        *ratelimiter.ReloadableRateLimiter
138
        reloadableWebhookRateLimiter *ratelimiter.ReloadableRateLimiter
139

140
        // indicates if controllers were started with or without CDI/DataSource support
141
        hasCDIDataSource bool
142
        // the channel used to trigger re-initialization.
143
        reInitChan chan string
144

145
        kubeVirtServiceAccounts map[string]struct{}
146
}
147

148
var (
149
        _                service.Service = &virtAPIApp{}
150
        apiHealthVersion                 = new(healthz.KubeApiHealthzVersion)
151
)
152

153
func NewVirtApi() VirtApi {
×
154

×
155
        app := &virtAPIApp{}
×
156
        app.BindAddress = defaultHost
×
157
        app.Port = defaultPort
×
158

×
159
        return app
×
160
}
×
161

162
func (app *virtAPIApp) Execute() {
×
163
        if err := metrics.SetupMetrics(); err != nil {
×
164
                panic(err)
×
165
        }
166

167
        app.reloadableRateLimiter = ratelimiter.NewReloadableRateLimiter(flowcontrol.NewTokenBucketRateLimiter(virtconfig.DefaultVirtAPIQPS, virtconfig.DefaultVirtAPIBurst))
×
168
        app.reloadableWebhookRateLimiter = ratelimiter.NewReloadableRateLimiter(flowcontrol.NewTokenBucketRateLimiter(virtconfig.DefaultVirtWebhookClientQPS, virtconfig.DefaultVirtWebhookClientBurst))
×
169

×
170
        clientmetrics.RegisterRestConfigHooks()
×
171
        clientConfig, err := kubecli.GetKubevirtClientConfig()
×
172
        if err != nil {
×
173
                panic(err)
×
174
        }
175
        clientConfig.RateLimiter = app.reloadableRateLimiter
×
176
        app.virtCli, err = kubecli.GetKubevirtClientFromRESTConfig(clientConfig)
×
177
        if err != nil {
×
178
                panic(err)
×
179
        }
180

181
        authorizor, err := rest.NewAuthorizor(app.reloadableWebhookRateLimiter)
×
182
        if err != nil {
×
183
                panic(err)
×
184
        }
185

186
        app.aggregatorClient = aggregatorclient.NewForConfigOrDie(clientConfig)
×
187

×
188
        app.authorizor = authorizor
×
189

×
190
        app.certsDirectory, err = os.MkdirTemp("", "certsdir")
×
191
        if err != nil {
×
192
                panic(err)
×
193
        }
194
        app.namespace, err = clientutil.GetNamespace()
×
195
        if err != nil {
×
196
                panic(err)
×
197
        }
198

199
        app.kubeVirtServiceAccounts = webhooks.KubeVirtServiceAccounts(app.namespace)
×
200

×
201
        app.ConfigureOpenAPIService()
×
202
        app.reInitChan = make(chan string, 10)
×
203

×
204
        app.Run()
×
205
}
206

207
func subresourceAPIGroup() metav1.APIGroup {
2✔
208
        apiGroup := metav1.APIGroup{
2✔
209
                Name: "subresource.kubevirt.io",
2✔
210
                PreferredVersion: metav1.GroupVersionForDiscovery{
2✔
211
                        GroupVersion: v1.SubresourceGroupVersions[0].Group + "/" + v1.SubresourceGroupVersions[0].Version,
2✔
212
                        Version:      v1.SubresourceGroupVersions[0].Version,
2✔
213
                },
2✔
214
        }
2✔
215

2✔
216
        for _, version := range v1.SubresourceGroupVersions {
6✔
217
                apiGroup.Versions = append(apiGroup.Versions, metav1.GroupVersionForDiscovery{
4✔
218
                        GroupVersion: version.Group + "/" + version.Version,
4✔
219
                        Version:      version.Version,
4✔
220
                })
4✔
221
        }
4✔
222
        apiGroup.ServerAddressByClientCIDRs = append(apiGroup.ServerAddressByClientCIDRs, metav1.ServerAddressByClientCIDR{
2✔
223
                ClientCIDR:    "0.0.0.0/0",
2✔
224
                ServerAddress: "",
2✔
225
        })
2✔
226
        apiGroup.Kind = "APIGroup"
2✔
227
        return apiGroup
2✔
228
}
229

230
func (app *virtAPIApp) composeSubresources() {
7✔
231

7✔
232
        var subwss []*restful.WebService
7✔
233

7✔
234
        for _, version := range v1.SubresourceGroupVersions {
21✔
235
                subresourcesvmGVR := schema.GroupVersionResource{Group: version.Group, Version: version.Version, Resource: "virtualmachines"}
14✔
236
                subresourcesvmiGVR := schema.GroupVersionResource{Group: version.Group, Version: version.Version, Resource: "virtualmachineinstances"}
14✔
237
                expandvmspecGVR := schema.GroupVersionResource{Group: version.Group, Version: version.Version, Resource: "expand-vm-spec"}
14✔
238

14✔
239
                subws := new(restful.WebService)
14✔
240
                subws.Doc(fmt.Sprintf("KubeVirt \"%s\" Subresource API.", version.Version))
14✔
241
                subws.Path(definitions.GroupVersionBasePath(version))
14✔
242

14✔
243
                subresourceApp := rest.NewSubresourceAPIApp(app.virtCli, app.consoleServerPort, app.handlerTLSConfiguration, app.clusterConfig)
14✔
244

14✔
245
                restartRouteBuilder := subws.PUT(definitions.NamespacedResourcePath(subresourcesvmGVR)+definitions.SubResourcePath("restart")).
14✔
246
                        To(subresourceApp.RestartVMRequestHandler).
14✔
247
                        Consumes(mime.MIME_ANY).
14✔
248
                        Reads(v1.RestartOptions{}).
14✔
249
                        Param(definitions.NamespaceParam(subws)).Param(definitions.NameParam(subws)).
14✔
250
                        Operation(version.Version+"Restart").
14✔
251
                        Doc("Restart a VirtualMachine object.").
14✔
252
                        Returns(http.StatusOK, "OK", "").
14✔
253
                        Returns(http.StatusNotFound, httpStatusNotFoundMessage, "").
14✔
254
                        Returns(http.StatusBadRequest, httpStatusBadRequestMessage, "")
14✔
255
                restartRouteBuilder.ParameterNamed("body").Required(false)
14✔
256
                subws.Route(restartRouteBuilder)
14✔
257

14✔
258
                subws.Route(subws.PUT(definitions.NamespacedResourcePath(subresourcesvmGVR)+definitions.SubResourcePath("migrate")).
14✔
259
                        To(subresourceApp.MigrateVMRequestHandler).
14✔
260
                        Consumes(mime.MIME_ANY).
14✔
261
                        Reads(v1.MigrateOptions{}).
14✔
262
                        Param(definitions.NamespaceParam(subws)).Param(definitions.NameParam(subws)).
14✔
263
                        Operation(version.Version+"Migrate").
14✔
264
                        Doc("Migrate a running VirtualMachine to another node.").
14✔
265
                        Returns(http.StatusOK, "OK", "").
14✔
266
                        Returns(http.StatusNotFound, httpStatusNotFoundMessage, "").
14✔
267
                        Returns(http.StatusBadRequest, httpStatusBadRequestMessage, ""))
14✔
268

14✔
269
                subws.Route(subws.PUT(definitions.NamespacedResourcePath(subresourcesvmGVR)+definitions.SubResourcePath("start")).
14✔
270
                        To(subresourceApp.StartVMRequestHandler).
14✔
271
                        Consumes(mime.MIME_ANY).
14✔
272
                        Reads(v1.StartOptions{}).
14✔
273
                        Param(definitions.NamespaceParam(subws)).Param(definitions.NameParam(subws)).
14✔
274
                        Operation(version.Version+"Start").
14✔
275
                        Doc("Start a VirtualMachine object.").
14✔
276
                        Returns(http.StatusOK, "OK", "").
14✔
277
                        Returns(http.StatusNotFound, httpStatusNotFoundMessage, "").
14✔
278
                        Returns(http.StatusBadRequest, httpStatusBadRequestMessage, ""))
14✔
279

14✔
280
                stopRouteBuilder := subws.PUT(definitions.NamespacedResourcePath(subresourcesvmGVR)+definitions.SubResourcePath("stop")).
14✔
281
                        To(subresourceApp.StopVMRequestHandler).
14✔
282
                        Consumes(mime.MIME_ANY).
14✔
283
                        Reads(v1.StopOptions{}).
14✔
284
                        Param(definitions.NamespaceParam(subws)).Param(definitions.NameParam(subws)).
14✔
285
                        Operation(version.Version+"Stop").
14✔
286
                        Doc("Stop a VirtualMachine object.").
14✔
287
                        Returns(http.StatusOK, "OK", "").
14✔
288
                        Returns(http.StatusNotFound, httpStatusNotFoundMessage, "").
14✔
289
                        Returns(http.StatusBadRequest, httpStatusBadRequestMessage, "")
14✔
290
                stopRouteBuilder.ParameterNamed("body").Required(false)
14✔
291
                subws.Route(stopRouteBuilder)
14✔
292

14✔
293
                subws.Route(subws.GET(definitions.NamespacedResourcePath(subresourcesvmGVR)+definitions.SubResourcePath("expand-spec")).
14✔
294
                        To(subresourceApp.ExpandSpecVMRequestHandler).
14✔
295
                        Param(definitions.NamespaceParam(subws)).Param(definitions.NameParam(subws)).
14✔
296
                        Operation(version.Version+"vm-ExpandSpec").
14✔
297
                        Produces(restful.MIME_JSON).
14✔
298
                        Doc("Get VirtualMachine object with expanded instancetype and preference.").
14✔
299
                        Returns(http.StatusOK, "OK", "").
14✔
300
                        Returns(http.StatusNotFound, httpStatusNotFoundMessage, "").
14✔
301
                        Returns(http.StatusInternalServerError, httpStatusInternalServerError, ""))
14✔
302

14✔
303
                subws.Route(subws.PUT(definitions.NamespacedResourcePath(subresourcesvmiGVR)+definitions.SubResourcePath("freeze")).
14✔
304
                        To(subresourceApp.FreezeVMIRequestHandler).
14✔
305
                        Consumes(mime.MIME_ANY).
14✔
306
                        Reads(v1.FreezeUnfreezeTimeout{}).
14✔
307
                        Param(definitions.NamespaceParam(subws)).Param(definitions.NameParam(subws)).
14✔
308
                        Operation(version.Version+"Freeze").
14✔
309
                        Doc("Freeze a VirtualMachineInstance object.").
14✔
310
                        Returns(http.StatusOK, "OK", "").
14✔
311
                        Returns(http.StatusInternalServerError, httpStatusInternalServerError, ""))
14✔
312

14✔
313
                subws.Route(subws.PUT(definitions.NamespacedResourcePath(subresourcesvmiGVR)+definitions.SubResourcePath("unfreeze")).
14✔
314
                        To(subresourceApp.UnfreezeVMIRequestHandler).
14✔
315
                        Param(definitions.NamespaceParam(subws)).Param(definitions.NameParam(subws)).
14✔
316
                        Operation(version.Version+"Unfreeze").
14✔
317
                        Doc("Unfreeze a VirtualMachineInstance object.").
14✔
318
                        Returns(http.StatusOK, "OK", "").
14✔
319
                        Returns(http.StatusInternalServerError, httpStatusInternalServerError, ""))
14✔
320

14✔
321
                subws.Route(subws.PUT(definitions.NamespacedResourcePath(subresourcesvmiGVR)+definitions.SubResourcePath("reset")).
14✔
322
                        To(subresourceApp.ResetVMIRequestHandler).
14✔
323
                        Param(definitions.NamespaceParam(subws)).Param(definitions.NameParam(subws)).
14✔
324
                        Operation(version.Version+"Reset").
14✔
325
                        Doc("Reset a VirtualMachineInstance object.").
14✔
326
                        Returns(http.StatusOK, "OK", "").
14✔
327
                        Returns(http.StatusInternalServerError, httpStatusInternalServerError, ""))
14✔
328

14✔
329
                subws.Route(subws.PUT(definitions.NamespacedResourcePath(subresourcesvmiGVR)+definitions.SubResourcePath("softreboot")).
14✔
330
                        To(subresourceApp.SoftRebootVMIRequestHandler).
14✔
331
                        Param(definitions.NamespaceParam(subws)).Param(definitions.NameParam(subws)).
14✔
332
                        Operation(version.Version+"SoftReboot").
14✔
333
                        Doc("Soft reboot a VirtualMachineInstance object.").
14✔
334
                        Returns(http.StatusOK, "OK", "").
14✔
335
                        Returns(http.StatusInternalServerError, httpStatusInternalServerError, ""))
14✔
336

14✔
337
                subws.Route(subws.PUT(definitions.NamespacedResourcePath(subresourcesvmiGVR)+definitions.SubResourcePath("pause")).
14✔
338
                        To(subresourceApp.PauseVMIRequestHandler).
14✔
339
                        Consumes(mime.MIME_ANY).
14✔
340
                        Reads(v1.PauseOptions{}).
14✔
341
                        Param(definitions.NamespaceParam(subws)).Param(definitions.NameParam(subws)).
14✔
342
                        Operation(version.Version+"Pause").
14✔
343
                        Doc("Pause a VirtualMachineInstance object.").
14✔
344
                        Returns(http.StatusOK, "OK", "").
14✔
345
                        Returns(http.StatusNotFound, httpStatusNotFoundMessage, "").
14✔
346
                        Returns(http.StatusBadRequest, httpStatusBadRequestMessage, ""))
14✔
347

14✔
348
                subws.Route(subws.PUT(definitions.NamespacedResourcePath(subresourcesvmiGVR)+definitions.SubResourcePath("unpause")).
14✔
349
                        To(subresourceApp.UnpauseVMIRequestHandler). // handles VMIs as well
14✔
350
                        Consumes(mime.MIME_ANY).
14✔
351
                        Reads(v1.UnpauseOptions{}).
14✔
352
                        Param(definitions.NamespaceParam(subws)).Param(definitions.NameParam(subws)).
14✔
353
                        Operation(version.Version+"Unpause").
14✔
354
                        Doc("Unpause a VirtualMachineInstance object.").
14✔
355
                        Returns(http.StatusOK, "OK", "").
14✔
356
                        Returns(http.StatusNotFound, httpStatusNotFoundMessage, "").
14✔
357
                        Returns(http.StatusBadRequest, httpStatusBadRequestMessage, ""))
14✔
358

14✔
359
                subws.Route(subws.GET(definitions.NamespacedResourcePath(subresourcesvmiGVR) + definitions.SubResourcePath("console")).
14✔
360
                        To(subresourceApp.ConsoleRequestHandler).
14✔
361
                        Param(definitions.NamespaceParam(subws)).Param(definitions.NameParam(subws)).
14✔
362
                        Operation(version.Version + "Console").
14✔
363
                        Doc("Open a websocket connection to a serial console on the specified VirtualMachineInstance."))
14✔
364

14✔
365
                subws.Route(subws.GET(definitions.NamespacedResourcePath(subresourcesvmiGVR) + definitions.SubResourcePath("vnc")).
14✔
366
                        To(subresourceApp.VNCRequestHandler).
14✔
367
                        Param(definitions.NamespaceParam(subws)).
14✔
368
                        Param(definitions.NameParam(subws)).
14✔
369
                        Param(definitions.PreserveSessionParam(subws)).
14✔
370
                        Operation(version.Version + "VNC").
14✔
371
                        Doc("Open a websocket connection to connect to VNC on the specified VirtualMachineInstance."))
14✔
372
                subws.Route(subws.GET(definitions.NamespacedResourcePath(subresourcesvmiGVR) + definitions.SubResourcePath("vnc/screenshot")).
14✔
373
                        To(subresourceApp.ScreenshotRequestHandler).
14✔
374
                        Param(definitions.NamespaceParam(subws)).
14✔
375
                        Param(definitions.NameParam(subws)).
14✔
376
                        Param(definitions.MoveCursorParam(subws)).
14✔
377
                        Operation(version.Version + "VNCScreenshot").
14✔
378
                        Doc("Get a PNG VNC screenshot of the specified VirtualMachineInstance."))
14✔
379
                subws.Route(subws.GET(definitions.NamespacedResourcePath(subresourcesvmiGVR) + definitions.SubResourcePath("usbredir")).
14✔
380
                        To(subresourceApp.USBRedirRequestHandler).
14✔
381
                        Param(definitions.NamespaceParam(subws)).
14✔
382
                        Param(definitions.NameParam(subws)).
14✔
383
                        Operation(version.Version + "usbredir").
14✔
384
                        Doc("Open a websocket connection to connect to USB device on the specified VirtualMachineInstance."))
14✔
385

14✔
386
                // VMI endpoint
14✔
387
                subws.Route(subws.GET(definitions.NamespacedResourcePath(subresourcesvmiGVR) + definitions.SubResourcePath("portforward") + definitions.PortPath).
14✔
388
                        To(subresourceApp.PortForwardRequestHandler(subresourceApp.FetchVirtualMachineInstance)).
14✔
389
                        Param(definitions.NamespaceParam(subws)).Param(definitions.NameParam(subws)).
14✔
390
                        Param(definitions.PortForwardPortParameter(subws)).
14✔
391
                        Operation(version.Version + "vmi-PortForward").
14✔
392
                        Doc("Open a websocket connection forwarding traffic to the specified VirtualMachineInstance and port."))
14✔
393
                subws.Route(subws.GET(definitions.NamespacedResourcePath(subresourcesvmiGVR) + definitions.SubResourcePath("portforward") + definitions.PortPath + definitions.ProtocolPath).
14✔
394
                        To(subresourceApp.PortForwardRequestHandler(subresourceApp.FetchVirtualMachineInstance)).
14✔
395
                        Param(definitions.NamespaceParam(subws)).Param(definitions.NameParam(subws)).
14✔
396
                        Param(definitions.PortForwardPortParameter(subws)).
14✔
397
                        Param(definitions.PortForwardProtocolParameter(subws)).
14✔
398
                        Operation(version.Version + "vmi-PortForwardWithProtocol").
14✔
399
                        Doc("Open a websocket connection forwarding traffic of the specified protocol (either tcp or udp) to the specified VirtualMachineInstance and port."))
14✔
400
                subws.Route(subws.GET(definitions.NamespacedResourcePath(subresourcesvmiGVR) + definitions.SubResourcePath("vsock")).
14✔
401
                        To(subresourceApp.VSOCKRequestHandler).
14✔
402
                        Param(definitions.NamespaceParam(subws)).Param(definitions.NameParam(subws)).Param(definitions.VSOCKPortParameter(subws)).Param(definitions.VSOCKTLSParameter(subws)).
14✔
403
                        Operation(version.Version + "VSOCK").
14✔
404
                        Doc("Open a websocket connection forwarding traffic to the specified VirtualMachineInstance and port via VSOCK."))
14✔
405

14✔
406
                // VM endpoint
14✔
407
                subws.Route(subws.GET(definitions.NamespacedResourcePath(subresourcesvmGVR) + definitions.SubResourcePath("portforward") + definitions.PortPath).
14✔
408
                        To(subresourceApp.PortForwardRequestHandler(subresourceApp.FetchVirtualMachineInstanceForVM)).
14✔
409
                        Param(definitions.NamespaceParam(subws)).Param(definitions.NameParam(subws)).
14✔
410
                        Param(definitions.PortForwardPortParameter(subws)).
14✔
411
                        Operation(version.Version + "vm-PortForward").
14✔
412
                        Doc("Open a websocket connection forwarding traffic to the running VMI for the specified VirtualMachine and port."))
14✔
413
                subws.Route(subws.GET(definitions.NamespacedResourcePath(subresourcesvmGVR) + definitions.SubResourcePath("portforward") + definitions.PortPath + definitions.ProtocolPath).
14✔
414
                        To(subresourceApp.PortForwardRequestHandler(subresourceApp.FetchVirtualMachineInstanceForVM)).
14✔
415
                        Param(definitions.NamespaceParam(subws)).Param(definitions.NameParam(subws)).
14✔
416
                        Param(definitions.PortForwardPortParameter(subws)).
14✔
417
                        Param(definitions.PortForwardProtocolParameter(subws)).
14✔
418
                        Operation(version.Version + "vm-PortForwardWithProtocol").
14✔
419
                        Doc("Open a websocket connection forwarding traffic of the specified protocol (either tcp or udp) to the specified VirtualMachine and port."))
14✔
420

14✔
421
                subws.Route(subws.PUT(definitions.NamespacedResourceBasePath(expandvmspecGVR)).
14✔
422
                        To(subresourceApp.ExpandSpecRequestHandler).
14✔
423
                        Param(definitions.NamespaceParam(subws)).
14✔
424
                        Operation(version.Version+"ExpandSpec").
14✔
425
                        Consumes(restful.MIME_JSON).
14✔
426
                        Produces(restful.MIME_JSON).
14✔
427
                        Doc("Expands instancetype and preference into the passed VirtualMachine object.").
14✔
428
                        Returns(http.StatusOK, "OK", "").
14✔
429
                        Returns(http.StatusBadRequest, httpStatusBadRequestMessage, "").
14✔
430
                        Returns(http.StatusInternalServerError, httpStatusInternalServerError, ""))
14✔
431

14✔
432
                subws.Route(subws.GET(definitions.SubResourcePath("version")).Produces(restful.MIME_JSON).
14✔
433
                        To(func(request *restful.Request, response *restful.Response) {
15✔
434
                                response.WriteAsJson(virtversion.Get())
1✔
435
                        }).Operation(version.Version + "Version"))
1✔
436

437
                subws.Route(subws.GET(definitions.SubResourcePath("start-cluster-profiler")).Produces(restful.MIME_JSON).
14✔
438
                        To(subresourceApp.StartClusterProfilerHandler).
14✔
439
                        Operation(version.Version + "start-cluster-profiler"))
14✔
440

14✔
441
                subws.Route(subws.GET(definitions.SubResourcePath("stop-cluster-profiler")).Produces(restful.MIME_JSON).
14✔
442
                        To(subresourceApp.StopClusterProfilerHandler).
14✔
443
                        Operation(version.Version + "stop-cluster-profiler"))
14✔
444

14✔
445
                subws.Route(subws.GET(definitions.SubResourcePath("dump-cluster-profiler")).Produces(restful.MIME_JSON).
14✔
446
                        To(subresourceApp.DumpClusterProfilerHandler).
14✔
447
                        Operation(version.Version + "dump-cluster-profiler"))
14✔
448

14✔
449
                subws.Route(subws.GET(definitions.SubResourcePath("guestfs")).Produces(restful.MIME_JSON).
14✔
450
                        To(app.GetGsInfo()).
14✔
451
                        Operation(version.Version+"Guestfs").
14✔
452
                        Returns(http.StatusOK, "OK", "").
14✔
453
                        Returns(http.StatusBadRequest, httpStatusBadRequestMessage, ""))
14✔
454
                subws.Route(subws.GET(definitions.SubResourcePath("healthz")).
14✔
455
                        To(healthz.KubeConnectionHealthzFuncFactory(app.clusterConfig, apiHealthVersion)).
14✔
456
                        Consumes(restful.MIME_JSON).
14✔
457
                        Produces(restful.MIME_JSON).
14✔
458
                        Operation(version.Version+"CheckHealth").
14✔
459
                        Doc("Health endpoint").
14✔
460
                        Returns(http.StatusOK, "OK", "").
14✔
461
                        Returns(http.StatusInternalServerError, "Unhealthy", ""))
14✔
462
                subws.Route(subws.GET(definitions.NamespacedResourcePath(subresourcesvmiGVR)+definitions.SubResourcePath("guestosinfo")).
14✔
463
                        To(subresourceApp.GuestOSInfo).
14✔
464
                        Param(definitions.NamespaceParam(subws)).Param(definitions.NameParam(subws)).
14✔
465
                        Consumes(restful.MIME_JSON).
14✔
466
                        Produces(restful.MIME_JSON).
14✔
467
                        Operation(version.Version+"Guestosinfo").
14✔
468
                        Doc("Get guest agent os information").
14✔
469
                        Writes(v1.VirtualMachineInstanceGuestAgentInfo{}).
14✔
470
                        Returns(http.StatusOK, "OK", v1.VirtualMachineInstanceGuestAgentInfo{}))
14✔
471

14✔
472
                subws.Route(subws.GET(definitions.NamespacedResourcePath(subresourcesvmiGVR)+definitions.SubResourcePath("userlist")).
14✔
473
                        To(subresourceApp.UserList).
14✔
474
                        Consumes(restful.MIME_JSON).
14✔
475
                        Produces(restful.MIME_JSON).
14✔
476
                        Param(definitions.NamespaceParam(subws)).Param(definitions.NameParam(subws)).
14✔
477
                        Operation(version.Version+"Userlist").
14✔
478
                        Doc("Get list of active users via guest agent").
14✔
479
                        Writes(v1.VirtualMachineInstanceGuestOSUserList{}).
14✔
480
                        Returns(http.StatusOK, "OK", v1.VirtualMachineInstanceGuestOSUserList{}))
14✔
481

14✔
482
                subws.Route(subws.GET(definitions.NamespacedResourcePath(subresourcesvmiGVR)+definitions.SubResourcePath("filesystemlist")).
14✔
483
                        To(subresourceApp.FilesystemList).
14✔
484
                        Consumes(restful.MIME_JSON).
14✔
485
                        Produces(restful.MIME_JSON).
14✔
486
                        Param(definitions.NamespaceParam(subws)).Param(definitions.NameParam(subws)).
14✔
487
                        Operation(version.Version+"Filesystemlist").
14✔
488
                        Doc("Get list of active filesystems on guest machine via guest agent").
14✔
489
                        Writes(v1.VirtualMachineInstanceFileSystemList{}).
14✔
490
                        Returns(http.StatusOK, "OK", v1.VirtualMachineInstanceFileSystemList{}))
14✔
491

14✔
492
                subws.Route(subws.GET(definitions.NamespacedResourcePath(subresourcesvmiGVR)+definitions.SubResourcePath("objectgraph")).
14✔
493
                        To(subresourceApp.VMIObjectGraph).
14✔
494
                        Consumes(restful.MIME_JSON).
14✔
495
                        Reads(v1.ObjectGraphOptions{}).
14✔
496
                        Produces(restful.MIME_JSON).
14✔
497
                        Param(definitions.NamespaceParam(subws)).Param(definitions.NameParam(subws)).
14✔
498
                        Operation(version.Version+"vmi-objectgraph").
14✔
499
                        Doc("Get graph of objects related to a Virtual Machine Instance").
14✔
500
                        Writes(v1.ObjectGraphNode{}).
14✔
501
                        Returns(http.StatusOK, "OK", v1.ObjectGraphNode{}))
14✔
502

14✔
503
                subws.Route(subws.GET(definitions.NamespacedResourcePath(subresourcesvmGVR)+definitions.SubResourcePath("objectgraph")).
14✔
504
                        To(subresourceApp.VMObjectGraph).
14✔
505
                        Consumes(restful.MIME_JSON).
14✔
506
                        Reads(v1.ObjectGraphOptions{}).
14✔
507
                        Produces(restful.MIME_JSON).
14✔
508
                        Param(definitions.NamespaceParam(subws)).Param(definitions.NameParam(subws)).
14✔
509
                        Operation(version.Version+"vm-objectgraph").
14✔
510
                        Doc("Get graph of objects related to a Virtual Machine").
14✔
511
                        Writes(v1.ObjectGraphNode{}).
14✔
512
                        Returns(http.StatusOK, "OK", v1.ObjectGraphNode{}))
14✔
513

14✔
514
                subws.Route(subws.PUT(definitions.NamespacedResourcePath(subresourcesvmiGVR)+definitions.SubResourcePath("addvolume")).
14✔
515
                        To(subresourceApp.VMIAddVolumeRequestHandler).
14✔
516
                        Consumes(mime.MIME_ANY).
14✔
517
                        Reads(v1.AddVolumeOptions{}).
14✔
518
                        Param(definitions.NamespaceParam(subws)).Param(definitions.NameParam(subws)).
14✔
519
                        Operation(version.Version+"vmi-addvolume").
14✔
520
                        Doc("Add a volume and disk to a running Virtual Machine Instance").
14✔
521
                        Returns(http.StatusOK, "OK", "").
14✔
522
                        Returns(http.StatusBadRequest, httpStatusBadRequestMessage, ""))
14✔
523

14✔
524
                subws.Route(subws.PUT(definitions.NamespacedResourcePath(subresourcesvmiGVR)+definitions.SubResourcePath("removevolume")).
14✔
525
                        To(subresourceApp.VMIRemoveVolumeRequestHandler).
14✔
526
                        Consumes(mime.MIME_ANY).
14✔
527
                        Reads(v1.RemoveVolumeOptions{}).
14✔
528
                        Param(definitions.NamespaceParam(subws)).Param(definitions.NameParam(subws)).
14✔
529
                        Operation(version.Version+"vmi-removevolume").
14✔
530
                        Doc("Removes a volume and disk from a running Virtual Machine Instance").
14✔
531
                        Returns(http.StatusOK, "OK", "").
14✔
532
                        Returns(http.StatusBadRequest, httpStatusBadRequestMessage, ""))
14✔
533

14✔
534
                subws.Route(subws.PUT(definitions.NamespacedResourcePath(subresourcesvmGVR)+definitions.SubResourcePath("addvolume")).
14✔
535
                        To(subresourceApp.VMAddVolumeRequestHandler).
14✔
536
                        Consumes(mime.MIME_ANY).
14✔
537
                        Reads(v1.AddVolumeOptions{}).
14✔
538
                        Param(definitions.NamespaceParam(subws)).Param(definitions.NameParam(subws)).
14✔
539
                        Operation(version.Version+"vm-addvolume").
14✔
540
                        Doc("Add a volume and disk to a running Virtual Machine.").
14✔
541
                        Returns(http.StatusOK, "OK", "").
14✔
542
                        Returns(http.StatusBadRequest, httpStatusBadRequestMessage, ""))
14✔
543

14✔
544
                subws.Route(subws.PUT(definitions.NamespacedResourcePath(subresourcesvmGVR)+definitions.SubResourcePath("removevolume")).
14✔
545
                        To(subresourceApp.VMRemoveVolumeRequestHandler).
14✔
546
                        Consumes(mime.MIME_ANY).
14✔
547
                        Reads(v1.RemoveVolumeOptions{}).
14✔
548
                        Param(definitions.NamespaceParam(subws)).Param(definitions.NameParam(subws)).
14✔
549
                        Operation(version.Version+"vm-removevolume").
14✔
550
                        Doc("Removes a volume and disk from a running Virtual Machine.").
14✔
551
                        Returns(http.StatusOK, "OK", "").
14✔
552
                        Returns(http.StatusBadRequest, httpStatusBadRequestMessage, ""))
14✔
553

14✔
554
                subws.Route(subws.PUT(definitions.NamespacedResourcePath(subresourcesvmGVR)+definitions.SubResourcePath("memorydump")).
14✔
555
                        To(subresourceApp.MemoryDumpVMRequestHandler).
14✔
556
                        Consumes(mime.MIME_ANY).
14✔
557
                        Reads(v1.VirtualMachineMemoryDumpRequest{}).
14✔
558
                        Param(definitions.NamespaceParam(subws)).Param(definitions.NameParam(subws)).
14✔
559
                        Operation(version.Version+"MemoryDump").
14✔
560
                        Doc("Dumps a VirtualMachineInstance memory.").
14✔
561
                        Returns(http.StatusOK, "OK", "").
14✔
562
                        Returns(http.StatusInternalServerError, httpStatusInternalServerError, ""))
14✔
563

14✔
564
                subws.Route(subws.PUT(definitions.NamespacedResourcePath(subresourcesvmGVR)+definitions.SubResourcePath("removememorydump")).
14✔
565
                        To(subresourceApp.RemoveMemoryDumpVMRequestHandler).
14✔
566
                        Param(definitions.NamespaceParam(subws)).Param(definitions.NameParam(subws)).
14✔
567
                        Operation(version.Version+"RemoveMemoryDump").
14✔
568
                        Doc("Remove memory dump association.").
14✔
569
                        Returns(http.StatusOK, "OK", "").
14✔
570
                        Returns(http.StatusInternalServerError, httpStatusInternalServerError, ""))
14✔
571

14✔
572
                // AMD SEV endpoints
14✔
573
                subws.Route(subws.GET(definitions.NamespacedResourcePath(subresourcesvmiGVR)+definitions.SubResourcePath("sev/fetchcertchain")).
14✔
574
                        To(subresourceApp.SEVFetchCertChainRequestHandler).
14✔
575
                        Param(definitions.NamespaceParam(subws)).Param(definitions.NameParam(subws)).
14✔
576
                        Consumes(restful.MIME_JSON).
14✔
577
                        Produces(restful.MIME_JSON).
14✔
578
                        Operation(version.Version+"SEVFetchCertChain").
14✔
579
                        Doc("Fetch SEV certificate chain from the node where Virtual Machine is scheduled").
14✔
580
                        Writes(v1.SEVPlatformInfo{}).
14✔
581
                        Returns(http.StatusOK, "OK", v1.SEVPlatformInfo{}))
14✔
582

14✔
583
                subws.Route(subws.GET(definitions.NamespacedResourcePath(subresourcesvmiGVR)+definitions.SubResourcePath("sev/querylaunchmeasurement")).
14✔
584
                        To(subresourceApp.SEVQueryLaunchMeasurementHandler).
14✔
585
                        Param(definitions.NamespaceParam(subws)).Param(definitions.NameParam(subws)).
14✔
586
                        Consumes(restful.MIME_JSON).
14✔
587
                        Produces(restful.MIME_JSON).
14✔
588
                        Operation(version.Version+"SEVQueryLaunchMeasurement").
14✔
589
                        Doc("Query SEV launch measurement from a Virtual Machine").
14✔
590
                        Writes(v1.SEVMeasurementInfo{}).
14✔
591
                        Returns(http.StatusOK, "OK", v1.SEVMeasurementInfo{}))
14✔
592

14✔
593
                subws.Route(subws.PUT(definitions.NamespacedResourcePath(subresourcesvmiGVR)+definitions.SubResourcePath("sev/setupsession")).
14✔
594
                        To(subresourceApp.SEVSetupSessionHandler).
14✔
595
                        Consumes(mime.MIME_ANY).
14✔
596
                        Reads(v1.SEVSessionOptions{}).
14✔
597
                        Param(definitions.NamespaceParam(subws)).Param(definitions.NameParam(subws)).
14✔
598
                        Operation(version.Version+"SEVSetupSession").
14✔
599
                        Doc("Setup SEV session parameters for a Virtual Machine").
14✔
600
                        Returns(http.StatusOK, "OK", "").
14✔
601
                        Returns(http.StatusBadRequest, httpStatusBadRequestMessage, ""))
14✔
602

14✔
603
                subws.Route(subws.PUT(definitions.NamespacedResourcePath(subresourcesvmiGVR)+definitions.SubResourcePath("sev/injectlaunchsecret")).
14✔
604
                        To(subresourceApp.SEVInjectLaunchSecretHandler).
14✔
605
                        Consumes(mime.MIME_ANY).
14✔
606
                        Reads(v1.SEVSecretOptions{}).
14✔
607
                        Param(definitions.NamespaceParam(subws)).Param(definitions.NameParam(subws)).
14✔
608
                        Operation(version.Version+"SEVInjectLaunchSecret").
14✔
609
                        Doc("Inject SEV launch secret into a Virtual Machine").
14✔
610
                        Returns(http.StatusOK, "OK", "").
14✔
611
                        Returns(http.StatusBadRequest, httpStatusBadRequestMessage, ""))
14✔
612

14✔
613
                subws.Route(subws.PUT(definitions.NamespacedResourcePath(subresourcesvmGVR)+definitions.SubResourcePath("evacuate/cancel")).
14✔
614
                        To(subresourceApp.EvacuateCancelHandler(subresourceApp.FetchVirtualMachineInstanceForVM)).
14✔
615
                        Consumes(mime.MIME_ANY).
14✔
616
                        Reads(v1.EvacuateCancelOptions{}).
14✔
617
                        Param(definitions.NamespaceParam(subws)).Param(definitions.NameParam(subws)).
14✔
618
                        Operation(version.Version+"vm-evacuatecancel").
14✔
619
                        Doc("Cancel evacuation Virtual Machine").
14✔
620
                        Returns(http.StatusOK, "OK", "").
14✔
621
                        Returns(http.StatusNotFound, httpStatusNotFoundMessage, "").
14✔
622
                        Returns(http.StatusBadRequest, httpStatusBadRequestMessage, "").
14✔
623
                        Returns(http.StatusInternalServerError, httpStatusInternalServerError, ""))
14✔
624

14✔
625
                subws.Route(subws.PUT(definitions.NamespacedResourcePath(subresourcesvmiGVR)+definitions.SubResourcePath("evacuate/cancel")).
14✔
626
                        To(subresourceApp.EvacuateCancelHandler(subresourceApp.FetchVirtualMachineInstance)).
14✔
627
                        Consumes(mime.MIME_ANY).
14✔
628
                        Reads(v1.EvacuateCancelOptions{}).
14✔
629
                        Param(definitions.NamespaceParam(subws)).Param(definitions.NameParam(subws)).
14✔
630
                        Operation(version.Version+"vmi-evacuatecancel").
14✔
631
                        Doc("Cancel evacuation Virtual Machine Instance").
14✔
632
                        Returns(http.StatusOK, "OK", "").
14✔
633
                        Returns(http.StatusNotFound, httpStatusNotFoundMessage, "").
14✔
634
                        Returns(http.StatusBadRequest, httpStatusBadRequestMessage, "").
14✔
635
                        Returns(http.StatusInternalServerError, httpStatusInternalServerError, ""))
14✔
636

14✔
637
                subws.Route(subws.PUT(definitions.NamespacedResourcePath(subresourcesvmiGVR)+definitions.SubResourcePath("backup")).
14✔
638
                        To(subresourceApp.BackupVMIRequestHandler).
14✔
639
                        Consumes(mime.MIME_ANY).
14✔
640
                        Reads(backupv1.BackupOptions{}).
14✔
641
                        Param(definitions.NamespaceParam(subws)).Param(definitions.NameParam(subws)).
14✔
642
                        Operation(version.Version+"Backup").
14✔
643
                        Doc("Initiate a VirtualMachineInstance backup.").
14✔
644
                        Returns(http.StatusOK, "OK", "").
14✔
645
                        Returns(http.StatusNotFound, httpStatusNotFoundMessage, "").
14✔
646
                        Returns(http.StatusBadRequest, httpStatusBadRequestMessage, ""))
14✔
647

14✔
648
                // Return empty api resource list.
14✔
649
                // K8s expects to be able to retrieve a resource list for each aggregated
14✔
650
                // app in order to discover what resources it provides. Without returning
14✔
651
                // an empty list here, there's a bug in the k8s resource discovery that
14✔
652
                // breaks kubectl's ability to reference short names for resources.
14✔
653
                subws.Route(subws.GET("/").
14✔
654
                        Produces(restful.MIME_JSON).Writes(metav1.APIResourceList{}).
14✔
655
                        To(func(request *restful.Request, response *restful.Response) {
15✔
656
                                list := &metav1.APIResourceList{}
1✔
657

1✔
658
                                list.Kind = "APIResourceList"
1✔
659
                                list.GroupVersion = version.Group + "/" + version.Version
1✔
660
                                list.APIVersion = "v1"
1✔
661
                                list.APIResources = []metav1.APIResource{
1✔
662
                                        {
1✔
663
                                                Name:       "expand-vm-spec",
1✔
664
                                                Namespaced: true,
1✔
665
                                        },
1✔
666
                                        {
1✔
667
                                                Name:       "virtualmachineinstances/vnc",
1✔
668
                                                Namespaced: true,
1✔
669
                                        },
1✔
670
                                        {
1✔
671
                                                Name:       "virtualmachineinstances/vnc/screenshot",
1✔
672
                                                Namespaced: true,
1✔
673
                                        },
1✔
674
                                        {
1✔
675
                                                Name:       "virtualmachineinstances/console",
1✔
676
                                                Namespaced: true,
1✔
677
                                        },
1✔
678
                                        {
1✔
679
                                                Name:       "virtualmachineinstances/portforward",
1✔
680
                                                Namespaced: true,
1✔
681
                                        },
1✔
682
                                        {
1✔
683
                                                Name:       "virtualmachineinstances/backup",
1✔
684
                                                Namespaced: true,
1✔
685
                                        },
1✔
686
                                        {
1✔
687
                                                Name:       "virtualmachineinstances/pause",
1✔
688
                                                Namespaced: true,
1✔
689
                                        },
1✔
690
                                        {
1✔
691
                                                Name:       "virtualmachineinstances/unpause",
1✔
692
                                                Namespaced: true,
1✔
693
                                        },
1✔
694
                                        {
1✔
695
                                                Name:       "virtualmachineinstances/freeze",
1✔
696
                                                Namespaced: true,
1✔
697
                                        },
1✔
698
                                        {
1✔
699
                                                Name:       "virtualmachineinstances/unfreeze",
1✔
700
                                                Namespaced: true,
1✔
701
                                        },
1✔
702
                                        {
1✔
703
                                                Name:       "virtualmachineinstances/reset",
1✔
704
                                                Namespaced: true,
1✔
705
                                        },
1✔
706
                                        {
1✔
707
                                                Name:       "virtualmachineinstances/softreboot",
1✔
708
                                                Namespaced: true,
1✔
709
                                        },
1✔
710
                                        {
1✔
711
                                                Name:       "virtualmachines/start",
1✔
712
                                                Namespaced: true,
1✔
713
                                        },
1✔
714
                                        {
1✔
715
                                                Name:       "virtualmachines/stop",
1✔
716
                                                Namespaced: true,
1✔
717
                                        },
1✔
718
                                        {
1✔
719
                                                Name:       "virtualmachines/restart",
1✔
720
                                                Namespaced: true,
1✔
721
                                        },
1✔
722
                                        {
1✔
723
                                                Name:       "virtualmachines/migrate",
1✔
724
                                                Namespaced: true,
1✔
725
                                        },
1✔
726
                                        {
1✔
727
                                                Name:       "virtualmachines/expand-spec",
1✔
728
                                                Namespaced: true,
1✔
729
                                        },
1✔
730
                                        {
1✔
731
                                                Name:       "virtualmachines/objectgraph",
1✔
732
                                                Namespaced: true,
1✔
733
                                        },
1✔
734
                                        {
1✔
735
                                                Name:       "virtualmachines/evacuate/cancel",
1✔
736
                                                Namespaced: true,
1✔
737
                                        },
1✔
738
                                        {
1✔
739
                                                Name:       "virtualmachineinstances/guestosinfo",
1✔
740
                                                Namespaced: true,
1✔
741
                                        },
1✔
742
                                        {
1✔
743
                                                Name:       "virtualmachineinstances/userlist",
1✔
744
                                                Namespaced: true,
1✔
745
                                        },
1✔
746
                                        {
1✔
747
                                                Name:       "virtualmachineinstances/filesystemlist",
1✔
748
                                                Namespaced: true,
1✔
749
                                        },
1✔
750
                                        {
1✔
751
                                                Name:       "virtualmachineinstances/addvolume",
1✔
752
                                                Namespaced: true,
1✔
753
                                        },
1✔
754
                                        {
1✔
755
                                                Name:       "virtualmachineinstances/removevolume",
1✔
756
                                                Namespaced: true,
1✔
757
                                        },
1✔
758
                                        {
1✔
759
                                                Name:       "virtualmachineinstances/objectgraph",
1✔
760
                                                Namespaced: true,
1✔
761
                                        },
1✔
762
                                        {
1✔
763
                                                Name:       "virtualmachineinstances/sev/fetchcertchain",
1✔
764
                                                Namespaced: true,
1✔
765
                                        },
1✔
766
                                        {
1✔
767
                                                Name:       "virtualmachineinstances/sev/querylaunchmeasurement",
1✔
768
                                                Namespaced: true,
1✔
769
                                        },
1✔
770
                                        {
1✔
771
                                                Name:       "virtualmachineinstances/sev/setupsession",
1✔
772
                                                Namespaced: true,
1✔
773
                                        },
1✔
774
                                        {
1✔
775
                                                Name:       "virtualmachineinstances/sev/injectlaunchsecret",
1✔
776
                                                Namespaced: true,
1✔
777
                                        },
1✔
778
                                        {
1✔
779
                                                Name:       "virtualmachineinstances/evacuate/cancel",
1✔
780
                                                Namespaced: true,
1✔
781
                                        },
1✔
782
                                }
1✔
783

1✔
784
                                response.WriteAsJson(list)
1✔
785
                        }).
1✔
786
                        Operation(version.Version+"getAPISubResources").
787
                        Doc("Get a KubeVirt API resources").
788
                        Returns(http.StatusOK, "OK", metav1.APIResourceList{}).
789
                        Returns(http.StatusNotFound, httpStatusNotFoundMessage, ""))
790

791
                restful.Add(subws)
14✔
792

14✔
793
                subwss = append(subwss, subws)
14✔
794
        }
795
        ws := new(restful.WebService)
7✔
796

7✔
797
        // K8s needs the ability to query the root paths
7✔
798
        ws.Route(ws.GET("/").
7✔
799
                Produces(restful.MIME_JSON).Writes(metav1.RootPaths{}).
7✔
800
                To(func(request *restful.Request, response *restful.Response) {
8✔
801
                        paths := []string{
1✔
802
                                "/apis",
1✔
803
                                "/openapi/v2",
1✔
804
                        }
1✔
805
                        for _, version := range v1.SubresourceGroupVersions {
3✔
806
                                paths = append(paths, definitions.GroupBasePath(version))
2✔
807
                                paths = append(paths, definitions.GroupVersionBasePath(version))
2✔
808
                        }
2✔
809
                        response.WriteAsJson(&metav1.RootPaths{
1✔
810
                                Paths: paths,
1✔
811
                        })
1✔
812
                }).
813
                Operation("getRootPaths").
814
                Doc("Get KubeVirt API root paths").
815
                Returns(http.StatusOK, "OK", metav1.RootPaths{}).
816
                Returns(http.StatusNotFound, httpStatusNotFoundMessage, ""))
817
        ws.Route(ws.GET("/healthz").To(healthz.KubeConnectionHealthzFuncFactory(app.clusterConfig, apiHealthVersion)).Doc("Health endpoint"))
7✔
818

7✔
819
        componentProfiler := profiler.NewProfileManager(app.clusterConfig)
7✔
820

7✔
821
        ws.Route(ws.GET("/start-profiler").To(componentProfiler.HandleStartProfiler).Doc("start profiler endpoint"))
7✔
822
        ws.Route(ws.GET("/stop-profiler").To(componentProfiler.HandleStopProfiler).Doc("stop profiler endpoint"))
7✔
823
        ws.Route(ws.GET("/dump-profiler").To(componentProfiler.HandleDumpProfiler).Doc("dump profiler results endpoint"))
7✔
824

7✔
825
        // K8s needs the ability to query info about a specific API group
7✔
826
        ws.Route(ws.GET(definitions.GroupBasePath(v1.SubresourceGroupVersions[0])).
7✔
827
                Produces(restful.MIME_JSON).Writes(metav1.APIGroup{}).
7✔
828
                To(func(request *restful.Request, response *restful.Response) {
8✔
829
                        response.WriteAsJson(subresourceAPIGroup())
1✔
830
                }).
1✔
831
                Operation(v1.SubresourceGroupVersions[0].Version+"GetSubAPIGroup").
832
                Doc("Get a KubeVirt API Group").
833
                Returns(http.StatusOK, "OK", metav1.APIGroup{}).
834
                Returns(http.StatusNotFound, httpStatusNotFoundMessage, ""))
835

836
        // K8s needs the ability to query the list of API groups this endpoint supports
837
        ws.Route(ws.GET("apis").
7✔
838
                Produces(restful.MIME_JSON).Writes(metav1.APIGroupList{}).
7✔
839
                To(func(request *restful.Request, response *restful.Response) {
8✔
840
                        list := &metav1.APIGroupList{}
1✔
841
                        list.Kind = "APIGroupList"
1✔
842
                        list.Groups = append(list.Groups, subresourceAPIGroup())
1✔
843
                        response.WriteAsJson(list)
1✔
844
                }).
1✔
845
                Operation("getAPIGroupList").
846
                Doc("Get a KubeVirt API GroupList").
847
                Returns(http.StatusOK, "OK", metav1.APIGroupList{}).
848
                Returns(http.StatusNotFound, httpStatusNotFoundMessage, ""))
849

850
        once := sync.Once{}
7✔
851
        var openapispec *spec.Swagger
7✔
852
        ws.Route(ws.GET("openapi/v2").
7✔
853
                Consumes(restful.MIME_JSON).
7✔
854
                Produces(restful.MIME_JSON).
7✔
855
                To(func(request *restful.Request, response *restful.Response) {
7✔
856
                        once.Do(func() {
×
857
                                openapispec = openapi.LoadOpenAPISpec([]*restful.WebService{ws, subwss[0]})
×
858
                                openapispec.Info.Version = virtversion.Get().String()
×
859
                        })
×
860
                        response.WriteAsJson(openapispec)
×
861
                }))
862

863
        restful.Add(ws)
7✔
864
}
865

866
func (app *virtAPIApp) Compose() {
7✔
867

7✔
868
        app.composeSubresources()
7✔
869

7✔
870
        restful.Filter(filter.RequestLoggingFilter())
7✔
871
        restful.Filter(restful.OPTIONSFilter())
7✔
872
        restful.Filter(func(req *restful.Request, resp *restful.Response, chain *restful.FilterChain) {
14✔
873
                allowed, reason, err := app.authorizor.Authorize(req)
7✔
874
                if err != nil {
8✔
875

1✔
876
                        log.Log.Reason(err).Error("internal error during auth request")
1✔
877
                        resp.WriteHeader(http.StatusInternalServerError)
1✔
878
                        return
1✔
879
                } else if allowed {
12✔
880
                        // request is permitted, so proceed with filter chain.
5✔
881
                        chain.ProcessFilter(req, resp)
5✔
882
                        return
5✔
883
                }
5✔
884
                resp.WriteErrorString(http.StatusUnauthorized, reason)
1✔
885
        })
886
}
887

888
func (app *virtAPIApp) ConfigureOpenAPIService() {
×
889
        config := openapi.CreateV3Config()
×
890
        config.GetDefinitions = v12.GetOpenAPIDefinitions
×
891
        spec, err := builderv3.BuildOpenAPISpecFromRoutes(restfuladapter.AdaptWebServices(restful.RegisteredWebServices()), config)
×
892
        if err != nil {
×
893
                panic(err)
×
894
        }
895

896
        ws := new(restful.WebService)
×
897
        ws.Path("/swaggerapi")
×
898
        ws.Produces(restful.MIME_JSON)
×
899
        f := func(req *restful.Request, resp *restful.Response) {
×
900
                resp.WriteAsJson(spec)
×
901
        }
×
902
        ws.Route(ws.GET("/").To(f))
×
903

×
904
        restful.DefaultContainer.Add(ws)
×
905
        http.Handle("/swagger-ui/", http.StripPrefix("/swagger-ui/", http.FileServer(http.Dir(app.SwaggerUI))))
×
906
}
907

908
func deserializeStrings(in string) ([]string, error) {
3✔
909
        if len(in) == 0 {
3✔
910
                return nil, nil
×
911
        }
×
912
        var ret []string
3✔
913
        if err := json.Unmarshal([]byte(in), &ret); err != nil {
3✔
914
                return nil, err
×
915
        }
×
916
        return ret, nil
3✔
917
}
918

919
func (app *virtAPIApp) readRequestHeader() error {
3✔
920
        authConfigMap, err := app.virtCli.CoreV1().ConfigMaps(metav1.NamespaceSystem).Get(context.Background(), util.ExtensionAPIServerAuthenticationConfigMap, metav1.GetOptions{})
3✔
921
        if err != nil {
4✔
922
                return err
1✔
923
        }
1✔
924

925
        // The request-header CA is mandatory. It can be retrieved from the configmap as we do here, or it must be provided
926
        // via flag on start of this apiserver. Since we don't do the latter, the former is mandatory for us
927
        // see https://github.com/kubernetes-incubator/apiserver-builder-alpha/blob/master/docs/concepts/auth.md#requestheader-authentication
928
        _, ok := authConfigMap.Data[util.RequestHeaderClientCAFileKey]
2✔
929
        if !ok {
3✔
930
                return fmt.Errorf("requestheader-client-ca-file not found in extension-apiserver-authentication ConfigMap")
1✔
931
        }
1✔
932

933
        // This config map also contains information about what
934
        // headers our authorizor should inspect
935
        headers, ok := authConfigMap.Data["requestheader-username-headers"]
1✔
936
        if ok {
2✔
937
                headerList, err := deserializeStrings(headers)
1✔
938
                if err != nil {
1✔
939
                        return err
×
940
                }
×
941
                app.authorizor.AddUserHeaders(headerList)
1✔
942
        }
943

944
        headers, ok = authConfigMap.Data["requestheader-group-headers"]
1✔
945
        if ok {
2✔
946
                headerList, err := deserializeStrings(headers)
1✔
947
                if err != nil {
1✔
948
                        return err
×
949
                }
×
950
                app.authorizor.AddGroupHeaders(headerList)
1✔
951
        }
952

953
        headers, ok = authConfigMap.Data["requestheader-extra-headers-prefix"]
1✔
954
        if ok {
2✔
955
                headerList, err := deserializeStrings(headers)
1✔
956
                if err != nil {
1✔
957
                        return err
×
958
                }
×
959
                app.authorizor.AddExtraPrefixHeaders(headerList)
1✔
960
        }
961
        return nil
1✔
962
}
963

964
func (app *virtAPIApp) prepareCertManager() {
×
965
        app.certmanager = bootstrap.NewFileCertificateManager(app.tlsCertFilePath, app.tlsKeyFilePath)
×
966
        app.handlerCertManager = bootstrap.NewFileCertificateManager(app.handlerCertFilePath, app.handlerKeyFilePath)
×
967
}
×
968

969
func (app *virtAPIApp) registerValidatingWebhooks(informers *webhooks.Informers) {
×
970
        http.HandleFunc(components.VMICreateValidatePath, func(w http.ResponseWriter, r *http.Request) {
×
971
                validating_webhook.ServeVMICreate(w, r, app.clusterConfig, app.kubeVirtServiceAccounts,
×
972
                        func(field *field.Path, vmiSpec *v1.VirtualMachineInstanceSpec, clusterCfg *virtconfig.ClusterConfig) []metav1.StatusCause {
×
973
                                return netadmitter.Validate(field, vmiSpec, clusterCfg)
×
974
                        },
×
975
                )
976
        })
977
        http.HandleFunc(components.VMIUpdateValidatePath, func(w http.ResponseWriter, r *http.Request) {
×
978
                validating_webhook.ServeVMIUpdate(w, r, app.clusterConfig, app.kubeVirtServiceAccounts)
×
979
        })
×
980
        http.HandleFunc(components.VMValidatePath, func(w http.ResponseWriter, r *http.Request) {
×
981
                validating_webhook.ServeVMs(w, r, app.clusterConfig, app.virtCli, informers, app.kubeVirtServiceAccounts)
×
982
        })
×
983
        http.HandleFunc(components.VMIRSValidatePath, func(w http.ResponseWriter, r *http.Request) {
×
984
                validating_webhook.ServeVMIRS(w, r, app.clusterConfig)
×
985
        })
×
986
        http.HandleFunc(components.VMPoolValidatePath, func(w http.ResponseWriter, r *http.Request) {
×
987
                validating_webhook.ServeVMPool(w, r, app.clusterConfig, app.kubeVirtServiceAccounts)
×
988
        })
×
989
        http.HandleFunc(components.VMIPresetValidatePath, func(w http.ResponseWriter, r *http.Request) {
×
990
                validating_webhook.ServeVMIPreset(w, r)
×
991
        })
×
992
        http.HandleFunc(components.MigrationCreateValidatePath, func(w http.ResponseWriter, r *http.Request) {
×
993
                validating_webhook.ServeMigrationCreate(w, r, app.clusterConfig, app.virtCli, app.kubeVirtServiceAccounts)
×
994
        })
×
995
        http.HandleFunc(components.MigrationUpdateValidatePath, func(w http.ResponseWriter, r *http.Request) {
×
996
                validating_webhook.ServeMigrationUpdate(w, r)
×
997
        })
×
998
        http.HandleFunc(components.VMSnapshotValidatePath, func(w http.ResponseWriter, r *http.Request) {
×
999
                validating_webhook.ServeVMSnapshots(w, r, app.clusterConfig, app.virtCli)
×
1000
        })
×
1001
        http.HandleFunc(components.VMRestoreValidatePath, func(w http.ResponseWriter, r *http.Request) {
×
1002
                validating_webhook.ServeVMRestores(w, r, app.clusterConfig, app.virtCli, informers)
×
1003
        })
×
1004
        http.HandleFunc(components.VMBackupValidatePath, func(w http.ResponseWriter, r *http.Request) {
×
1005
                validating_webhook.ServeVMBackups(w, r, app.clusterConfig, app.virtCli, informers)
×
1006
        })
×
NEW
1007
        http.HandleFunc(components.VMBackupTrackerValidatePath, func(w http.ResponseWriter, r *http.Request) {
×
NEW
1008
                validating_webhook.ServeVMBackupTrackers(w, r, app.clusterConfig)
×
NEW
1009
        })
×
1010
        http.HandleFunc(components.VMExportValidatePath, func(w http.ResponseWriter, r *http.Request) {
×
1011
                validating_webhook.ServeVMExports(w, r, app.clusterConfig)
×
1012
        })
×
1013
        http.HandleFunc(components.VMInstancetypeValidatePath, func(w http.ResponseWriter, r *http.Request) {
×
1014
                validating_webhook.ServeVmInstancetypes(w, r)
×
1015
        })
×
1016
        http.HandleFunc(components.VMClusterInstancetypeValidatePath, func(w http.ResponseWriter, r *http.Request) {
×
1017
                validating_webhook.ServeVmClusterInstancetypes(w, r)
×
1018
        })
×
1019
        http.HandleFunc(components.VMPreferenceValidatePath, func(w http.ResponseWriter, r *http.Request) {
×
1020
                validating_webhook.ServeVmPreferences(w, r)
×
1021
        })
×
1022
        http.HandleFunc(components.VMClusterPreferenceValidatePath, func(w http.ResponseWriter, r *http.Request) {
×
1023
                validating_webhook.ServeVmClusterPreferences(w, r)
×
1024
        })
×
1025
        http.HandleFunc(components.StatusValidatePath, func(w http.ResponseWriter, r *http.Request) {
×
1026
                validating_webhook.ServeStatusValidation(w, r, app.clusterConfig, app.virtCli, informers, app.kubeVirtServiceAccounts)
×
1027
        })
×
1028
        http.HandleFunc(components.PodEvictionValidatePath, func(w http.ResponseWriter, r *http.Request) {
×
1029
                validating_webhook.ServePodEvictionInterceptor(w, r, app.clusterConfig, app.virtCli)
×
1030
        })
×
1031
        http.HandleFunc(components.MigrationPolicyCreateValidatePath, func(w http.ResponseWriter, r *http.Request) {
×
1032
                validating_webhook.ServeMigrationPolicies(w, r)
×
1033
        })
×
1034
        http.HandleFunc(components.VMCloneCreateValidatePath, func(w http.ResponseWriter, r *http.Request) {
×
1035
                validating_webhook.ServeVirtualMachineClones(w, r, app.clusterConfig, app.virtCli)
×
1036
        })
×
1037
}
1038

1039
func (app *virtAPIApp) registerMutatingWebhook(informers *webhooks.Informers) {
×
1040

×
1041
        http.HandleFunc(components.VMMutatePath, func(w http.ResponseWriter, r *http.Request) {
×
1042
                mutating_webhook.ServeVMs(w, r, app.clusterConfig, app.virtCli)
×
1043
        })
×
1044
        http.HandleFunc(components.VMIMutatePath, func(w http.ResponseWriter, r *http.Request) {
×
1045
                mutating_webhook.ServeVMIs(w, r, app.clusterConfig, informers, app.kubeVirtServiceAccounts)
×
1046
        })
×
1047
        http.HandleFunc(components.MigrationMutatePath, func(w http.ResponseWriter, r *http.Request) {
×
1048
                mutating_webhook.ServeMigrationCreate(w, r)
×
1049
        })
×
1050
        http.HandleFunc(components.VMCloneCreateMutatePath, func(w http.ResponseWriter, r *http.Request) {
×
1051
                mutating_webhook.ServeClones(w, r)
×
1052
        })
×
1053
}
1054

1055
func (app *virtAPIApp) setupTLS(k8sCAManager kvtls.KubernetesCAManager, kubevirtCAManager kvtls.ClientCAManager) {
×
1056

×
1057
        // A VerifyClientCertIfGiven request means we're not guaranteed
×
1058
        // a client has been authenticated unless they provide a peer
×
1059
        // cert.
×
1060
        //
×
1061
        // Make sure to verify in subresource endpoint that peer cert
×
1062
        // was provided before processing request. If the peer cert is
×
1063
        // given on the connection, then we can be guaranteed that it
×
1064
        // was signed by the client CA in our pool.
×
1065
        //
×
1066
        // There is another ClientAuth type called 'RequireAndVerifyClientCert'
×
1067
        // We can't use this type here because during the aggregated api status
×
1068
        // check it attempts to hit '/' on our api endpoint to verify an http
×
1069
        // response is given. That status request won't send a peer cert regardless
×
1070
        // if the TLS handshake requests it. As a result, the TLS handshake fails
×
1071
        // and our aggregated endpoint never becomes available.
×
1072
        app.tlsConfig = kvtls.SetupTLSWithCertManager(k8sCAManager, app.certmanager, tls.VerifyClientCertIfGiven, app.clusterConfig)
×
1073
        app.handlerTLSConfiguration = kvtls.SetupTLSForVirtHandlerClients(kubevirtCAManager, app.handlerCertManager, app.externallyManaged)
×
1074
}
×
1075

1076
func (app *virtAPIApp) startTLS(informerFactory controller.KubeInformerFactory) error {
×
1077

×
1078
        errors := make(chan error)
×
1079
        c := make(chan os.Signal, 1)
×
1080

×
1081
        signal.Notify(c, os.Interrupt,
×
1082
                syscall.SIGHUP,
×
1083
                syscall.SIGINT,
×
1084
                syscall.SIGTERM,
×
1085
                syscall.SIGQUIT,
×
1086
        )
×
1087

×
1088
        authConfigMapInformer := informerFactory.ApiAuthConfigMap()
×
1089
        kubevirtCAConfigInformer := informerFactory.KubeVirtCAConfigMap()
×
1090

×
1091
        k8sCAManager := kvtls.NewKubernetesClientCAManager(authConfigMapInformer.GetStore())
×
1092
        kubevirtCAInformer := kvtls.NewCAManager(kubevirtCAConfigInformer.GetStore(), app.namespace, app.caConfigMapName)
×
1093
        app.setupTLS(k8sCAManager, kubevirtCAInformer)
×
1094

×
1095
        app.Compose()
×
1096

×
1097
        http.Handle("/metrics", promhttp.Handler())
×
1098
        server := &http.Server{
×
1099
                Addr:      fmt.Sprintf("%s:%d", app.BindAddress, app.Port),
×
1100
                TLSConfig: app.tlsConfig,
×
1101
                // Disable HTTP/2
×
1102
                // See CVE-2023-44487
×
1103
                TLSNextProto: map[string]func(*http.Server, *tls.Conn, http.Handler){},
×
1104
        }
×
1105

×
1106
        // start TLS server
×
1107
        go func() {
×
1108
                errors <- server.ListenAndServeTLS("", "")
×
1109
        }()
×
1110

1111
        // start graceful shutdown handler
1112
        go func() {
×
1113
                select {
×
1114
                case s := <-c:
×
1115
                        log.Log.Infof("Received signal %s, initiating graceful shutdown", s.String())
×
1116
                case msg := <-app.reInitChan:
×
1117
                        log.Log.Infof("Received signal to reInitialize virt-api [%s], initiating graceful shutdown", msg)
×
1118
                }
1119

1120
                // pause briefly to ensure the load balancer has had a chance to
1121
                // remove this endpoint from rotation due to pod.DeletionTimestamp != nil
1122
                // By pausing, we reduce the chance that the load balancer will attempt to
1123
                // route new requests to the service after we've started the shutdown
1124
                // procedure
1125
                time.Sleep(5 * time.Second)
×
1126

×
1127
                // by default, server.Shutdown() waits indefinitely for all existing
×
1128
                // connections to close. We need to give this a timeout to ensure the
×
1129
                // shutdown will eventually complete.
×
1130
                ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
×
1131
                defer func() {
×
1132
                        cancel()
×
1133
                }()
×
1134

1135
                // Shutdown means new connections are not permitted and it waits for existing
1136
                // connections to terminate (up to the context timeout)
1137
                server.Shutdown(ctx)
×
1138
                // Shutdown forces any existing connections that persist after the shutdown
×
1139
                // times out to be forced closed.
×
1140
                server.Close()
×
1141
        }()
1142

1143
        // wait for server to exit
1144
        err := <-errors
×
1145

×
1146
        if err != nil && err != http.ErrServerClosed {
×
1147
                // ErrServerClosed is an expected error during normal shutdown
×
1148
                return err
×
1149
        }
×
1150
        return nil
×
1151
}
1152

1153
func (app *virtAPIApp) Run() {
×
1154
        host, err := os.Hostname()
×
1155
        if err != nil {
×
1156
                panic(fmt.Errorf("unable to get hostname: %v", err))
×
1157
        }
1158
        app.host = host
×
1159

×
1160
        // get client Cert
×
1161
        err = app.readRequestHeader()
×
1162
        if err != nil {
×
1163
                panic(err)
×
1164
        }
1165

1166
        // Get/Set selfsigned cert
1167
        app.prepareCertManager()
×
1168

×
1169
        // Run informers for webhooks usage
×
1170
        kubeInformerFactory := controller.NewKubeInformerFactory(app.virtCli.RestClient(), app.virtCli, app.aggregatorClient, app.namespace)
×
1171

×
1172
        kubeVirtInformer := kubeInformerFactory.KubeVirt()
×
1173
        // Wire up health check trigger
×
1174
        kubeVirtInformer.SetWatchErrorHandler(func(r *cache.Reflector, err error) {
×
1175
                apiHealthVersion.Clear()
×
1176
                cache.DefaultWatchErrorHandler(context.TODO(), r, err)
×
1177
        })
×
1178

1179
        kubeInformerFactory.ApiAuthConfigMap()
×
1180
        kubeInformerFactory.KubeVirtCAConfigMap()
×
1181
        crdInformer := kubeInformerFactory.CRD()
×
1182
        vmiPresetInformer := kubeInformerFactory.VirtualMachinePreset()
×
1183
        vmRestoreInformer := kubeInformerFactory.VirtualMachineRestore()
×
1184
        vmBackupInformer := kubeInformerFactory.VirtualMachineBackup()
×
1185
        namespaceInformer := kubeInformerFactory.Namespace()
×
1186

×
1187
        stopChan := make(chan struct{}, 1)
×
1188
        defer close(stopChan)
×
1189
        kubeInformerFactory.Start(stopChan)
×
1190
        kubeInformerFactory.WaitForCacheSync(stopChan)
×
1191

×
1192
        app.clusterConfig, err = virtconfig.NewClusterConfig(crdInformer, kubeVirtInformer, app.namespace)
×
1193
        if err != nil {
×
1194
                panic(err)
×
1195
        }
1196
        app.hasCDIDataSource = app.clusterConfig.HasDataSourceAPI()
×
1197
        app.clusterConfig.SetConfigModifiedCallback(app.configModificationCallback)
×
1198
        app.clusterConfig.SetConfigModifiedCallback(app.shouldChangeLogVerbosity)
×
1199
        app.clusterConfig.SetConfigModifiedCallback(app.shouldChangeRateLimiter)
×
1200

×
1201
        var dataSourceInformer cache.SharedIndexInformer
×
1202
        if app.hasCDIDataSource {
×
1203
                dataSourceInformer = kubeInformerFactory.DataSource()
×
1204
                log.Log.Infof("CDI detected, DataSource integration enabled")
×
1205
        } else {
×
1206
                // Add a dummy DataSource informer in the event datasource support
×
1207
                // is disabled. This lets the controller continue to work without
×
1208
                // requiring a separate branching code path.
×
1209
                dataSourceInformer = kubeInformerFactory.DummyDataSource()
×
1210
                log.Log.Infof("CDI not detected, DataSource integration disabled")
×
1211
        }
×
1212

1213
        // It is safe to call kubeInformerFactory.Start multiple times.
1214
        // The function is idempotent and will only start the informers that
1215
        // have not been started yet
1216
        kubeInformerFactory.Start(stopChan)
×
1217
        kubeInformerFactory.WaitForCacheSync(stopChan)
×
1218

×
1219
        webhookInformers := &webhooks.Informers{
×
1220
                VMIPresetInformer:  vmiPresetInformer,
×
1221
                VMRestoreInformer:  vmRestoreInformer,
×
1222
                VMBackupInformer:   vmBackupInformer,
×
1223
                DataSourceInformer: dataSourceInformer,
×
1224
                NamespaceInformer:  namespaceInformer,
×
1225
        }
×
1226

×
1227
        // Build webhook subresources
×
1228
        app.registerMutatingWebhook(webhookInformers)
×
1229
        app.registerValidatingWebhooks(webhookInformers)
×
1230

×
1231
        go app.certmanager.Start()
×
1232
        go app.handlerCertManager.Start()
×
1233

×
1234
        // start TLS server
×
1235
        // tls server will only accept connections when fetching a certificate and internal configuration passed once
×
1236
        err = app.startTLS(kubeInformerFactory)
×
1237
        if err != nil {
×
1238
                panic(err)
×
1239
        }
1240

1241
}
1242

1243
// Detects if a config has been applied that requires
1244
// re-initializing virt-api.
1245
func (app *virtAPIApp) configModificationCallback() {
×
1246
        newHasCDI := app.clusterConfig.HasDataSourceAPI()
×
1247
        if newHasCDI != app.hasCDIDataSource {
×
1248
                if newHasCDI {
×
1249
                        log.Log.Infof("Reinitialize virt-api, cdi DataSource api has been introduced")
×
1250
                } else {
×
1251
                        log.Log.Infof("Reinitialize virt-api, cdi DataSource api has been removed")
×
1252
                }
×
1253
                app.reInitChan <- "reinit due to CDI api change"
×
1254
        }
1255
}
1256

1257
// Update virt-api log verbosity on relevant config changes
1258
func (app *virtAPIApp) shouldChangeLogVerbosity() {
×
1259
        verbosity := app.clusterConfig.GetVirtAPIVerbosity(app.host)
×
1260
        log.Log.SetVerbosityLevel(int(verbosity))
×
1261
        log.Log.V(2).Infof("set log verbosity to %d", verbosity)
×
1262
}
×
1263

1264
// Update virt-handler rate limiter
1265
func (app *virtAPIApp) shouldChangeRateLimiter() {
×
1266
        config := app.clusterConfig.GetConfig()
×
1267
        qps := config.APIConfiguration.RestClient.RateLimiter.TokenBucketRateLimiter.QPS
×
1268
        burst := config.APIConfiguration.RestClient.RateLimiter.TokenBucketRateLimiter.Burst
×
1269
        app.reloadableRateLimiter.Set(flowcontrol.NewTokenBucketRateLimiter(qps, burst))
×
1270
        log.Log.V(2).Infof("setting rate limiter for the API to %v QPS and %v Burst", qps, burst)
×
1271
        qps = config.WebhookConfiguration.RestClient.RateLimiter.TokenBucketRateLimiter.QPS
×
1272
        burst = config.WebhookConfiguration.RestClient.RateLimiter.TokenBucketRateLimiter.Burst
×
1273
        app.reloadableWebhookRateLimiter.Set(flowcontrol.NewTokenBucketRateLimiter(qps, burst))
×
1274
        log.Log.V(2).Infof("setting rate limiter for webhooks to %v QPS and %v Burst", qps, burst)
×
1275
}
×
1276

1277
func (app *virtAPIApp) AddFlags() {
1✔
1278
        app.InitFlags()
1✔
1279

1✔
1280
        app.AddCommonFlags()
1✔
1281

1✔
1282
        flag.StringVar(&app.SwaggerUI, "swagger-ui", "third_party/swagger-ui",
1✔
1283
                "swagger-ui location")
1✔
1284
        flag.BoolVar(&app.SubresourcesOnly, "subresources-only", false,
1✔
1285
                "Only serve subresource endpoints")
1✔
1286
        flag.IntVar(&app.consoleServerPort, "console-server-port", DefaultConsoleServerPort,
1✔
1287
                "The port virt-handler listens on for console requests")
1✔
1288
        flag.StringVar(&app.caConfigMapName, "ca-configmap-name", defaultCAConfigMapName,
1✔
1289
                "The name of configmap containing CA certificates to authenticate requests presenting client certificates with matching CommonName")
1✔
1290
        flag.StringVar(&app.tlsCertFilePath, "tls-cert-file", defaultTlsCertFilePath,
1✔
1291
                "File containing the default x509 Certificate for HTTPS")
1✔
1292
        flag.StringVar(&app.tlsKeyFilePath, "tls-key-file", defaultTlsKeyFilePath,
1✔
1293
                "File containing the default x509 private key matching --tls-cert-file")
1✔
1294
        flag.StringVar(&app.handlerCertFilePath, "handler-cert-file", defaultHandlerCertFilePath,
1✔
1295
                "Client certificate used to prove the identity of the virt-api when it must call virt-handler during a request")
1✔
1296
        flag.StringVar(&app.handlerKeyFilePath, "handler-key-file", defaultHandlerKeyFilePath,
1✔
1297
                "Private key for the client certificate used to prove the identity of the virt-api when it must call virt-handler during a request")
1✔
1298
        flag.BoolVar(&app.externallyManaged, "externally-managed", false,
1✔
1299
                "Allow intermediate certificates to be used in building up the chain of trust when certificates are externally managed")
1✔
1300
}
1✔
1301

1302
// GetGsInfo returns the libguestfs-tools image information based on the KubeVirt installation in the namespace.
1303
func (app *virtAPIApp) GetGsInfo() func(_ *restful.Request, response *restful.Response) {
14✔
1304
        return func(_ *restful.Request, response *restful.Response) {
14✔
1305
                var kvConfig virtoperatorutils.KubeVirtDeploymentConfig
×
1306
                kv := app.clusterConfig.GetConfigFromKubeVirtCR()
×
1307
                if kv == nil {
×
1308
                        error_guestfs(fmt.Errorf("Failed getting KubeVirt config"), response)
×
1309
                }
×
1310
                err := json.Unmarshal([]byte(kv.Status.ObservedDeploymentConfig), &kvConfig)
×
1311
                if err != nil {
×
1312
                        error_guestfs(err, response)
×
1313
                        return
×
1314
                }
×
1315
                response.WriteAsJson(kubecli.GuestfsInfo{
×
1316
                        Registry:    kv.Status.ObservedKubeVirtRegistry,
×
1317
                        Tag:         kv.Status.ObservedKubeVirtVersion,
×
1318
                        ImagePrefix: kvConfig.GetImagePrefix(),
×
1319
                        GsImage:     kvConfig.GsImage,
×
1320
                })
×
1321
                return
×
1322
        }
1323
}
1324

1325
func error_guestfs(err error, response *restful.Response) {
×
1326
        res := map[string]interface{}{}
×
1327
        res["guestfs"] = map[string]interface{}{"status": "failed", "error": fmt.Sprintf("%v", err)}
×
1328
        response.WriteHeaderAndJson(http.StatusInternalServerError, res, restful.MIME_JSON)
×
1329
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc