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

kubevirt / kubevirt / 55c8662e-3cac-41c2-9b0b-b09f98b851a1

09 Dec 2025 08:21AM UTC coverage: 70.666% (-0.01%) from 70.68%
55c8662e-3cac-41c2-9b0b-b09f98b851a1

push

prow

web-flow
Merge pull request #16081 from ShellyKa13/vmbackup

VMBackup: introduce new VM backup API

1189 of 1731 new or added lines in 35 files covered. (68.69%)

12 existing lines in 4 files now uncovered.

71582 of 101296 relevant lines covered (70.67%)

416.77 hits per line

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

11.26
/pkg/virt-controller/watch/application.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 watch
21

22
import (
23
        "context"
24
        "crypto/tls"
25
        golog "log"
26
        "net/http"
27
        "os"
28
        "path/filepath"
29
        "time"
30

31
        v1 "kubevirt.io/api/core/v1"
32

33
        "kubevirt.io/kubevirt/pkg/hooks"
34

35
        containerdisk "kubevirt.io/kubevirt/pkg/container-disk"
36
        kvtls "kubevirt.io/kubevirt/pkg/util/tls"
37

38
        clone "kubevirt.io/api/clone/v1beta1"
39

40
        clonecontroller "kubevirt.io/kubevirt/pkg/virt-controller/watch/clone"
41
        "kubevirt.io/kubevirt/pkg/virt-controller/watch/migration"
42
        "kubevirt.io/kubevirt/pkg/virt-controller/watch/node"
43
        "kubevirt.io/kubevirt/pkg/virt-controller/watch/pool"
44
        "kubevirt.io/kubevirt/pkg/virt-controller/watch/replicaset"
45
        "kubevirt.io/kubevirt/pkg/virt-controller/watch/vm"
46
        "kubevirt.io/kubevirt/pkg/virt-controller/watch/vmi"
47

48
        "github.com/emicklei/go-restful/v3"
49
        vsv1 "github.com/kubernetes-csi/external-snapshotter/client/v4/apis/volumesnapshot/v1"
50
        "github.com/prometheus/client_golang/prometheus/promhttp"
51
        flag "github.com/spf13/pflag"
52
        k8sv1 "k8s.io/api/core/v1"
53
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
54
        utilruntime "k8s.io/apimachinery/pkg/util/runtime"
55
        k8sfield "k8s.io/apimachinery/pkg/util/validation/field"
56
        "k8s.io/client-go/kubernetes/scheme"
57
        k8coresv1 "k8s.io/client-go/kubernetes/typed/core/v1"
58
        clientrest "k8s.io/client-go/rest"
59
        "k8s.io/client-go/tools/cache"
60
        "k8s.io/client-go/tools/leaderelection"
61
        "k8s.io/client-go/tools/leaderelection/resourcelock"
62
        "k8s.io/client-go/tools/record"
63
        "k8s.io/client-go/util/flowcontrol"
64

65
        "kubevirt.io/kubevirt/pkg/virt-controller/watch/dra"
66

67
        "kubevirt.io/kubevirt/pkg/util/ratelimiter"
68

69
        "kubevirt.io/kubevirt/pkg/virt-controller/watch/topology"
70

71
        "kubevirt.io/kubevirt/pkg/healthz"
72
        "kubevirt.io/kubevirt/pkg/monitoring/profiler"
73

74
        backupv1 "kubevirt.io/api/backup/v1alpha1"
75
        exportv1 "kubevirt.io/api/export/v1beta1"
76
        poolv1 "kubevirt.io/api/pool/v1beta1"
77
        snapshotv1 "kubevirt.io/api/snapshot/v1beta1"
78
        "kubevirt.io/client-go/kubecli"
79
        "kubevirt.io/client-go/log"
80
        clientutil "kubevirt.io/client-go/util"
81

82
        "kubevirt.io/kubevirt/pkg/certificates/bootstrap"
83
        "kubevirt.io/kubevirt/pkg/controller"
84
        clusterutil "kubevirt.io/kubevirt/pkg/util/cluster"
85

86
        instancetypecontroller "kubevirt.io/kubevirt/pkg/instancetype/controller/vm"
87
        clientmetrics "kubevirt.io/kubevirt/pkg/monitoring/metrics/common/client"
88
        metrics "kubevirt.io/kubevirt/pkg/monitoring/metrics/virt-controller"
89
        "kubevirt.io/kubevirt/pkg/service"
90
        backup "kubevirt.io/kubevirt/pkg/storage/cbt"
91
        "kubevirt.io/kubevirt/pkg/storage/export/export"
92
        "kubevirt.io/kubevirt/pkg/storage/snapshot"
93
        "kubevirt.io/kubevirt/pkg/util"
94
        virtconfig "kubevirt.io/kubevirt/pkg/virt-config"
95
        "kubevirt.io/kubevirt/pkg/virt-controller/leaderelectionconfig"
96
        "kubevirt.io/kubevirt/pkg/virt-controller/services"
97
        "kubevirt.io/kubevirt/pkg/virt-controller/watch/drain/disruptionbudget"
98
        "kubevirt.io/kubevirt/pkg/virt-controller/watch/drain/evacuation"
99
        workloadupdater "kubevirt.io/kubevirt/pkg/virt-controller/watch/workload-updater"
100

101
        netadmitter "kubevirt.io/kubevirt/pkg/network/admitter"
102
        netcontrollers "kubevirt.io/kubevirt/pkg/network/controllers"
103
        netmigration "kubevirt.io/kubevirt/pkg/network/migration"
104
        "kubevirt.io/kubevirt/pkg/network/netbinding"
105
        netannotations "kubevirt.io/kubevirt/pkg/network/pod/annotations"
106
        storageannotations "kubevirt.io/kubevirt/pkg/storage/pod/annotations"
107
)
108

109
const (
110
        defaultPort = 8182
111

112
        defaultHost = "0.0.0.0"
113

114
        launcherImage       = "virt-launcher"
115
        exporterImage       = "virt-exportserver"
116
        launcherQemuTimeout = 240
117

118
        migrationControllerRestTimeout = 30 * time.Second
119

120
        imagePullSecret = ""
121

122
        virtShareDir = "/var/run/kubevirt"
123

124
        ephemeralDiskDir = virtShareDir + "-ephemeral-disks"
125

126
        defaultControllerThreads         = 3
127
        defaultSnapshotControllerThreads = 6
128
        defaultBackupControllerThreads   = 6
129
        defaultVMIControllerThreads      = 10
130

131
        defaultLauncherSubGid                 = 107
132
        defaultSnapshotControllerResyncPeriod = 5 * time.Minute
133
        defaultNodeTopologyUpdatePeriod       = 30 * time.Second
134

135
        defaultPromCertFilePath = "/etc/virt-controller/certificates/tls.crt"
136
        defaultPromKeyFilePath  = "/etc/virt-controller/certificates/tls.key"
137
)
138

139
var (
140
        containerDiskDir = filepath.Join(util.VirtShareDir, "container-disks")
141
        hotplugDiskDir   = filepath.Join(util.VirtShareDir, "hotplug-disks")
142

143
        apiHealthVersion = new(healthz.KubeApiHealthzVersion)
144
)
145

146
type VirtControllerApp struct {
147
        service.ServiceListen
148

149
        clientSet             kubecli.KubevirtClient
150
        templateService       *services.TemplateService
151
        restClient            *clientrest.RESTClient
152
        informerFactory       controller.KubeInformerFactory
153
        kvPodInformer         cache.SharedIndexInformer
154
        resourceClaimInformer cache.SharedIndexInformer
155
        resourceSliceInformer cache.SharedIndexInformer
156

157
        nodeInformer   cache.SharedIndexInformer
158
        nodeController *node.Controller
159

160
        vmiCache            cache.Store
161
        vmiController       *vmi.Controller
162
        draStatusController *dra.DRAStatusController
163
        vmiInformer         cache.SharedIndexInformer
164
        vmiRecorder         record.EventRecorder
165

166
        namespaceInformer cache.SharedIndexInformer
167
        namespaceStore    cache.Store
168

169
        kubeVirtInformer cache.SharedIndexInformer
170

171
        clusterConfig *virtconfig.ClusterConfig
172

173
        pdbInformer cache.SharedIndexInformer
174

175
        persistentVolumeClaimCache    cache.Store
176
        persistentVolumeClaimInformer cache.SharedIndexInformer
177

178
        rsController *replicaset.Controller
179
        rsInformer   cache.SharedIndexInformer
180

181
        poolController *pool.Controller
182
        poolInformer   cache.SharedIndexInformer
183

184
        vmController *vm.Controller
185
        vmInformer   cache.SharedIndexInformer
186

187
        controllerRevisionInformer cache.SharedIndexInformer
188

189
        dataVolumeInformer     cache.SharedIndexInformer
190
        dataSourceInformer     cache.SharedIndexInformer
191
        storageProfileInformer cache.SharedIndexInformer
192
        cdiInformer            cache.SharedIndexInformer
193
        cdiConfigInformer      cache.SharedIndexInformer
194

195
        migrationController *migration.Controller
196
        migrationInformer   cache.SharedIndexInformer
197

198
        workloadUpdateController *workloadupdater.WorkloadUpdateController
199

200
        caExportConfigMapInformer    cache.SharedIndexInformer
201
        exportRouteConfigMapInformer cache.SharedInformer
202
        exportServiceInformer        cache.SharedIndexInformer
203
        exportController             *export.VMExportController
204
        snapshotController           *snapshot.VMSnapshotController
205
        restoreController            *snapshot.VMRestoreController
206
        vmExportInformer             cache.SharedIndexInformer
207
        routeCache                   cache.Store
208
        ingressCache                 cache.Store
209
        unmanagedSecretInformer      cache.SharedIndexInformer
210
        vmSnapshotInformer           cache.SharedIndexInformer
211
        vmSnapshotContentInformer    cache.SharedIndexInformer
212
        vmRestoreInformer            cache.SharedIndexInformer
213
        storageClassInformer         cache.SharedIndexInformer
214
        allPodInformer               cache.SharedIndexInformer
215
        resourceQuotaInformer        cache.SharedIndexInformer
216

217
        crdInformer cache.SharedIndexInformer
218

219
        migrationPolicyInformer cache.SharedIndexInformer
220

221
        vmCloneInformer   cache.SharedIndexInformer
222
        vmCloneController *clonecontroller.VMCloneController
223

224
        vmBackupInformer   cache.SharedIndexInformer
225
        vmBackupController *backup.VMBackupController
226

227
        instancetypeInformer        cache.SharedIndexInformer
228
        clusterInstancetypeInformer cache.SharedIndexInformer
229
        preferenceInformer          cache.SharedIndexInformer
230
        clusterPreferenceInformer   cache.SharedIndexInformer
231

232
        LeaderElection leaderelectionconfig.Configuration
233

234
        launcherImage              string
235
        exporterImage              string
236
        launcherQemuTimeout        int
237
        imagePullSecret            string
238
        virtShareDir               string
239
        ephemeralDiskDir           string
240
        containerDiskDir           string
241
        hotplugDiskDir             string
242
        readyChan                  chan bool
243
        kubevirtNamespace          string
244
        host                       string
245
        evacuationController       *evacuation.EvacuationController
246
        disruptionBudgetController *disruptionbudget.DisruptionBudgetController
247

248
        ctx context.Context
249

250
        // indicates if controllers were started with or without CDI/DataVolume support
251
        hasCDI bool
252
        // indicates if controllers were started with or without DRA support
253
        isDRAEnabled bool
254
        // the channel used to trigger re-initialization.
255
        reInitChan chan string
256

257
        // number of threads for each controller
258
        nodeControllerThreads             int
259
        vmiControllerThreads              int
260
        draStatusControllerThreads        int
261
        rsControllerThreads               int
262
        poolControllerThreads             int
263
        vmControllerThreads               int
264
        migrationControllerThreads        int
265
        evacuationControllerThreads       int
266
        disruptionBudgetControllerThreads int
267
        launcherSubGid                    int64
268
        exportControllerThreads           int
269
        snapshotControllerThreads         int
270
        restoreControllerThreads          int
271
        snapshotControllerResyncPeriod    time.Duration
272
        cloneControllerThreads            int
273
        additionalLauncherAnnotationsSync []string
274
        additionalLauncherLabelsSync      []string
275
        backupControllerThreads           int
276

277
        caConfigMapName          string
278
        promCertFilePath         string
279
        promKeyFilePath          string
280
        nodeTopologyUpdater      topology.NodeTopologyUpdater
281
        nodeTopologyUpdatePeriod time.Duration
282
        reloadableRateLimiter    *ratelimiter.ReloadableRateLimiter
283
        leaderElector            *leaderelection.LeaderElector
284

285
        onOpenshift bool
286
}
287

288
var _ service.Service = &VirtControllerApp{}
289

290
func init() {
1✔
291
        utilruntime.Must(vsv1.AddToScheme(scheme.Scheme))
1✔
292
        utilruntime.Must(snapshotv1.AddToScheme(scheme.Scheme))
1✔
293
        utilruntime.Must(exportv1.AddToScheme(scheme.Scheme))
1✔
294
        utilruntime.Must(poolv1.AddToScheme(scheme.Scheme))
1✔
295
        utilruntime.Must(clone.AddToScheme(scheme.Scheme))
1✔
296
        utilruntime.Must(backupv1.AddToScheme(scheme.Scheme))
1✔
297
}
1✔
298

299
func Execute() {
×
300
        var err error
×
301
        var app = VirtControllerApp{}
×
302

×
303
        app.LeaderElection = leaderelectionconfig.DefaultLeaderElectionConfiguration()
×
304

×
305
        service.Setup(&app)
×
306

×
307
        app.readyChan = make(chan bool, 1)
×
308

×
309
        log.InitializeLogging("virt-controller")
×
310

×
311
        app.reloadableRateLimiter = ratelimiter.NewReloadableRateLimiter(flowcontrol.NewTokenBucketRateLimiter(virtconfig.DefaultVirtControllerQPS, virtconfig.DefaultVirtControllerBurst))
×
312
        clientmetrics.RegisterRestConfigHooks()
×
313
        clientConfig, err := kubecli.GetKubevirtClientConfig()
×
314
        if err != nil {
×
315
                panic(err)
×
316
        }
317
        clientConfig.RateLimiter = app.reloadableRateLimiter
×
318
        app.clientSet, err = kubecli.GetKubevirtClientFromRESTConfig(clientConfig)
×
319
        if err != nil {
×
320
                golog.Fatal(err)
×
321
        }
×
322

323
        app.restClient = app.clientSet.RestClient()
×
324

×
325
        // Bootstrapping. From here on the initialization order is important
×
326
        app.kubevirtNamespace, err = clientutil.GetNamespace()
×
327
        if err != nil {
×
328
                golog.Fatalf("Error searching for namespace: %v", err)
×
329
        }
×
330

331
        host, err := os.Hostname()
×
332
        if err != nil {
×
333
                golog.Fatalf("unable to get hostname: %v", err)
×
334
        }
×
335
        app.host = host
×
336

×
337
        ctx, cancel := context.WithCancel(context.Background())
×
338
        stopChan := ctx.Done()
×
339
        app.ctx = ctx
×
340

×
341
        app.informerFactory = controller.NewKubeInformerFactory(app.restClient, app.clientSet, nil, app.kubevirtNamespace)
×
342

×
343
        app.crdInformer = app.informerFactory.CRD()
×
344
        app.kubeVirtInformer = app.informerFactory.KubeVirt()
×
345

×
346
        if err := app.kubeVirtInformer.SetWatchErrorHandler(func(r *cache.Reflector, err error) {
×
347
                apiHealthVersion.Clear()
×
348
                cache.DefaultWatchErrorHandler(context.TODO(), r, err)
×
349
        }); err != nil {
×
350
                golog.Fatalf("failed to set the watch error handler: %v", err)
×
351
        }
×
352
        app.informerFactory.Start(stopChan)
×
353

×
354
        cache.WaitForCacheSync(stopChan, app.crdInformer.HasSynced, app.kubeVirtInformer.HasSynced)
×
355
        app.clusterConfig, err = virtconfig.NewClusterConfig(app.crdInformer, app.kubeVirtInformer, app.kubevirtNamespace)
×
356
        if err != nil {
×
357
                panic(err)
×
358
        }
359

360
        app.reInitChan = make(chan string, 10)
×
361
        app.hasCDI = app.clusterConfig.HasDataVolumeAPI()
×
362
        app.isDRAEnabled = app.clusterConfig.GPUsWithDRAGateEnabled() || app.clusterConfig.HostDevicesWithDRAEnabled()
×
363
        app.clusterConfig.SetConfigModifiedCallback(app.configModificationCallback)
×
364
        app.clusterConfig.SetConfigModifiedCallback(app.shouldChangeLogVerbosity)
×
365
        app.clusterConfig.SetConfigModifiedCallback(app.shouldChangeRateLimiter)
×
366

×
367
        webService := new(restful.WebService)
×
368
        webService.Path("/").Consumes(restful.MIME_JSON).Produces(restful.MIME_JSON)
×
369
        webService.Route(webService.GET("/healthz").To(healthz.KubeConnectionHealthzFuncFactory(app.clusterConfig, apiHealthVersion)).Doc("Health endpoint"))
×
370
        webService.Route(webService.GET("/leader").To(app.leaderProbe).Doc("Leader endpoint"))
×
371

×
372
        componentProfiler := profiler.NewProfileManager(app.clusterConfig)
×
373
        webService.Route(webService.GET("/start-profiler").To(componentProfiler.HandleStartProfiler).Doc("start profiler endpoint"))
×
374
        webService.Route(webService.GET("/stop-profiler").To(componentProfiler.HandleStopProfiler).Doc("stop profiler endpoint"))
×
375
        webService.Route(webService.GET("/dump-profiler").To(componentProfiler.HandleDumpProfiler).Doc("dump profiler results endpoint"))
×
376

×
377
        restful.Add(webService)
×
378

×
379
        app.vmiInformer = app.informerFactory.VMI()
×
380
        app.kvPodInformer = app.informerFactory.KubeVirtPod()
×
381
        if app.isDRAEnabled {
×
382
                app.resourceClaimInformer = app.informerFactory.ResourceClaim()
×
383
                app.resourceSliceInformer = app.informerFactory.ResourceSlice()
×
384
                log.Log.Infof("One of DRA FG detected, DRA integration enabled")
×
385
        } else {
×
386
                app.resourceClaimInformer = app.informerFactory.DummyResourceClaim()
×
387
                app.resourceSliceInformer = app.informerFactory.DummyResourceSlice()
×
388
                log.Log.Infof("No DRA FG detected, DRA integration disabled")
×
389
        }
×
390
        app.nodeInformer = app.informerFactory.KubeVirtNode()
×
391
        app.namespaceStore = app.informerFactory.Namespace().GetStore()
×
392
        app.namespaceInformer = app.informerFactory.Namespace()
×
393
        app.vmiCache = app.vmiInformer.GetStore()
×
394
        app.vmiRecorder = app.newRecorder(k8sv1.NamespaceAll, "virtualmachine-controller")
×
395

×
396
        app.rsInformer = app.informerFactory.VMIReplicaSet()
×
397
        app.poolInformer = app.informerFactory.VMPool()
×
398

×
399
        app.persistentVolumeClaimInformer = app.informerFactory.PersistentVolumeClaim()
×
400
        app.persistentVolumeClaimCache = app.persistentVolumeClaimInformer.GetStore()
×
401

×
402
        app.pdbInformer = app.informerFactory.K8SInformerFactory().Policy().V1().PodDisruptionBudgets().Informer()
×
403

×
404
        app.vmInformer = app.informerFactory.VirtualMachine()
×
405

×
406
        app.migrationInformer = app.informerFactory.VirtualMachineInstanceMigration()
×
407

×
408
        app.controllerRevisionInformer = app.informerFactory.ControllerRevision()
×
409

×
NEW
410
        app.vmBackupInformer = app.informerFactory.VirtualMachineBackup()
×
411
        app.vmExportInformer = app.informerFactory.VirtualMachineExport()
×
412
        app.vmSnapshotInformer = app.informerFactory.VirtualMachineSnapshot()
×
413
        app.vmSnapshotContentInformer = app.informerFactory.VirtualMachineSnapshotContent()
×
414
        app.vmRestoreInformer = app.informerFactory.VirtualMachineRestore()
×
415
        app.storageClassInformer = app.informerFactory.StorageClass()
×
416
        app.caExportConfigMapInformer = app.informerFactory.KubeVirtExportCAConfigMap()
×
417
        app.exportRouteConfigMapInformer = app.informerFactory.ExportRouteConfigMap()
×
418
        app.unmanagedSecretInformer = app.informerFactory.UnmanagedSecrets()
×
419
        app.allPodInformer = app.informerFactory.Pod()
×
420
        app.exportServiceInformer = app.informerFactory.ExportService()
×
421
        app.resourceQuotaInformer = app.informerFactory.ResourceQuota()
×
422

×
423
        if app.hasCDI {
×
424
                app.dataVolumeInformer = app.informerFactory.DataVolume()
×
425
                app.cdiInformer = app.informerFactory.CDI()
×
426
                app.cdiConfigInformer = app.informerFactory.CDIConfig()
×
427
                app.dataSourceInformer = app.informerFactory.DataSource()
×
428
                app.storageProfileInformer = app.informerFactory.StorageProfile()
×
429
                log.Log.Infof("CDI detected, DataVolume integration enabled")
×
430
        } else {
×
431
                // Add a dummy DataVolume informer in the event datavolume support
×
432
                // is disabled. This lets the controller continue to work without
×
433
                // requiring a separate branching code path.
×
434
                app.dataVolumeInformer = app.informerFactory.DummyDataVolume()
×
435
                app.cdiInformer = app.informerFactory.DummyCDI()
×
436
                app.cdiConfigInformer = app.informerFactory.DummyCDIConfig()
×
437
                app.dataSourceInformer = app.informerFactory.DummyDataSource()
×
438
                app.storageProfileInformer = app.informerFactory.DummyStorageProfile()
×
439
                log.Log.Infof("CDI not detected, DataVolume integration disabled")
×
440
        }
×
441

442
        onOpenShift, err := clusterutil.IsOnOpenShift(app.clientSet)
×
443
        if err != nil {
×
444
                golog.Fatalf("Error determining cluster type: %v", err)
×
445
        }
×
446
        if onOpenShift {
×
447
                log.Log.Info("we are on openshift")
×
448
                app.routeCache = app.informerFactory.OperatorRoute().GetStore()
×
449
        } else {
×
450
                log.Log.Info("we are on kubernetes")
×
451
                app.routeCache = app.informerFactory.DummyOperatorRoute().GetStore()
×
452
        }
×
453
        app.ingressCache = app.informerFactory.Ingress().GetStore()
×
454
        app.migrationPolicyInformer = app.informerFactory.MigrationPolicy()
×
455

×
456
        app.vmCloneInformer = app.informerFactory.VirtualMachineClone()
×
457

×
458
        app.instancetypeInformer = app.informerFactory.VirtualMachineInstancetype()
×
459
        app.clusterInstancetypeInformer = app.informerFactory.VirtualMachineClusterInstancetype()
×
460
        app.preferenceInformer = app.informerFactory.VirtualMachinePreference()
×
461
        app.clusterPreferenceInformer = app.informerFactory.VirtualMachineClusterPreference()
×
462

×
463
        app.onOpenshift = onOpenShift
×
464

×
465
        metricsInformers := &metrics.Indexers{
×
466
                VMIMigration: app.migrationInformer.GetIndexer(),
×
467
                KVPod:        app.kvPodInformer.GetIndexer(),
×
468
        }
×
469

×
470
        metricsStores := &metrics.Stores{
×
471
                VM:                    app.vmInformer.GetStore(),
×
472
                VMI:                   app.vmiInformer.GetStore(),
×
473
                PersistentVolumeClaim: app.persistentVolumeClaimInformer.GetStore(),
×
474
                Instancetype:          app.instancetypeInformer.GetStore(),
×
475
                ClusterInstancetype:   app.clusterInstancetypeInformer.GetStore(),
×
476
                Preference:            app.preferenceInformer.GetStore(),
×
477
                ClusterPreference:     app.clusterPreferenceInformer.GetStore(),
×
478
                ControllerRevision:    app.controllerRevisionInformer.GetStore(),
×
479
        }
×
480

×
481
        if err := metrics.SetupMetrics(
×
482
                metricsInformers,
×
483
                metricsStores,
×
484
                app.clusterConfig,
×
485
                app.clientSet,
×
486
        ); err != nil {
×
487
                golog.Fatal(err)
×
488
        }
×
489

490
        app.initCommon()
×
491
        app.initReplicaSet()
×
492
        app.initPool()
×
493
        app.initVirtualMachines()
×
494
        app.initDisruptionBudgetController()
×
495
        app.initEvacuationController()
×
496
        app.initSnapshotController()
×
497
        app.initRestoreController()
×
498
        app.initExportController()
×
499
        app.initWorkloadUpdaterController()
×
500
        app.initCloneController()
×
NEW
501
        app.initBackupController()
×
502
        go app.Run()
×
503

×
504
        <-app.reInitChan
×
505
        cancel()
×
506
}
507

508
// Detects if a config has been applied that requires
509
// re-initializing virt-controller.
510
func (vca *VirtControllerApp) configModificationCallback() {
4✔
511
        newHasCDI := vca.clusterConfig.HasDataVolumeAPI()
4✔
512
        if newHasCDI != vca.hasCDI {
6✔
513
                if newHasCDI {
3✔
514
                        log.Log.Infof("Reinitialize virt-controller, cdi api has been introduced")
1✔
515
                } else {
2✔
516
                        log.Log.Infof("Reinitialize virt-controller, cdi api has been removed")
1✔
517
                }
1✔
518
                vca.reInitChan <- "reinit"
2✔
519
                return
2✔
520
        }
521
        newIsDRAEnabled := vca.clusterConfig.GPUsWithDRAGateEnabled() || vca.clusterConfig.HostDevicesWithDRAEnabled()
2✔
522
        if newIsDRAEnabled != vca.isDRAEnabled {
2✔
523
                if newIsDRAEnabled {
×
524
                        log.Log.Infof("Reinitialize virt-controller, DRA integration has been introduced")
×
525
                } else {
×
526
                        log.Log.Infof("Reinitialize virt-controller, DRA integration has been removed")
×
527
                }
×
528
                vca.reInitChan <- "reinit"
×
529
                return
×
530
        }
531
}
532

533
// Update virt-controller rate limiter
534
func (vca *VirtControllerApp) shouldChangeRateLimiter() {
×
535
        config := vca.clusterConfig.GetConfig()
×
536
        qps := config.ControllerConfiguration.RestClient.RateLimiter.TokenBucketRateLimiter.QPS
×
537
        burst := config.ControllerConfiguration.RestClient.RateLimiter.TokenBucketRateLimiter.Burst
×
538
        vca.reloadableRateLimiter.Set(flowcontrol.NewTokenBucketRateLimiter(qps, burst))
×
539
        log.Log.V(2).Infof("setting rate limiter to %v QPS and %v Burst", qps, burst)
×
540
}
×
541

542
// Update virt-controller log verbosity on relevant config changes
543
func (vca *VirtControllerApp) shouldChangeLogVerbosity() {
×
544
        verbosity := vca.clusterConfig.GetVirtControllerVerbosity(vca.host)
×
545
        if err := log.Log.SetVerbosityLevel(int(verbosity)); err != nil {
×
546
                log.Log.Warningf("failed up update log verbosity to %d: %v", verbosity, err)
×
547
        } else {
×
548
                log.Log.V(2).Infof("set log verbosity to %d", verbosity)
×
549
        }
×
550
}
551

552
func (vca *VirtControllerApp) Run() {
×
553
        logger := log.Log
×
554

×
555
        promCertManager := bootstrap.NewFileCertificateManager(vca.promCertFilePath, vca.promKeyFilePath)
×
556
        go promCertManager.Start()
×
557
        promTLSConfig := kvtls.SetupPromTLS(promCertManager, vca.clusterConfig)
×
558

×
559
        go func() {
×
560
                httpLogger := logger.With("service", "http")
×
561
                _ = httpLogger.Level(log.INFO).Log("action", "listening", "interface", vca.BindAddress, "port", vca.Port)
×
562
                http.Handle("/metrics", promhttp.Handler())
×
563
                server := http.Server{
×
564
                        Addr:      vca.Address(),
×
565
                        Handler:   http.DefaultServeMux,
×
566
                        TLSConfig: promTLSConfig,
×
567
                        // Disable HTTP/2
×
568
                        // See CVE-2023-44487
×
569
                        TLSNextProto: map[string]func(*http.Server, *tls.Conn, http.Handler){},
×
570
                }
×
571
                if err := server.ListenAndServeTLS("", ""); err != nil {
×
572
                        golog.Fatal(err)
×
573
                }
×
574
        }()
575

576
        if err := vca.setupLeaderElector(); err != nil {
×
577
                golog.Fatal(err)
×
578
        }
×
579

580
        metrics.SetVirtControllerReady()
×
581
        vca.leaderElector.Run(vca.ctx)
×
582
        metrics.SetVirtControllerNotReady()
×
583
        panic("unreachable")
×
584
}
585

586
func (vca *VirtControllerApp) onStartedLeading() func(ctx context.Context) {
1✔
587
        return func(ctx context.Context) {
2✔
588
                stop := ctx.Done()
1✔
589
                vca.informerFactory.Start(stop)
1✔
590

1✔
591
                golog.Printf("STARTING controllers with following threads : "+
1✔
592
                        "node %d, vmi %d, replicaset %d, vm %d, migration %d, evacuation %d, disruptionBudget %d",
1✔
593
                        vca.nodeControllerThreads, vca.vmiControllerThreads, vca.rsControllerThreads,
1✔
594
                        vca.vmControllerThreads, vca.migrationControllerThreads, vca.evacuationControllerThreads,
1✔
595
                        vca.disruptionBudgetControllerThreads)
1✔
596

1✔
597
                if err := metrics.RegisterLeaderMetrics(); err != nil {
1✔
598
                        golog.Fatalf("failed to register leader metrics: %v", err)
×
599
                }
×
600

601
                if err := metrics.AddVMIPhaseTransitionHandlers(vca.vmiInformer); err != nil {
1✔
602
                        golog.Fatalf("failed to add vmi phase transition handler: %v", err)
×
603
                }
×
604

605
                if vca.migrationInformer == nil {
2✔
606
                        vca.migrationInformer = vca.informerFactory.VirtualMachineInstanceMigration()
1✔
607
                        metrics.UpdateVMIMigrationInformer(vca.migrationInformer.GetIndexer())
1✔
608
                }
1✔
609
                golog.Printf("\nvca.migrationInformer :%v\n", vca.migrationInformer)
1✔
610

1✔
611
                if err := metrics.CreateVMIMigrationHandler(vca.migrationInformer); err != nil {
1✔
612
                        golog.Fatalf("failed to add vmi phase transition time handler: %v", err)
×
613
                }
×
614

615
                go vca.evacuationController.Run(vca.evacuationControllerThreads, stop)
1✔
616
                go vca.disruptionBudgetController.Run(vca.disruptionBudgetControllerThreads, stop)
1✔
617
                go vca.nodeController.Run(vca.nodeControllerThreads, stop)
1✔
618
                go vca.vmiController.Run(vca.vmiControllerThreads, stop)
1✔
619
                if vca.isDRAEnabled {
1✔
620
                        go vca.draStatusController.Run(vca.draStatusControllerThreads, stop)
×
621
                }
×
622
                go vca.rsController.Run(vca.rsControllerThreads, stop)
1✔
623
                go vca.poolController.Run(vca.poolControllerThreads, stop)
1✔
624
                go vca.vmController.Run(vca.vmControllerThreads, stop)
1✔
625
                go vca.migrationController.Run(vca.migrationControllerThreads, stop)
1✔
626
                go func() {
2✔
627
                        if err := vca.snapshotController.Run(vca.snapshotControllerThreads, stop); err != nil {
2✔
628
                                log.Log.Warningf("error running the snapshot controller: %v", err)
1✔
629
                        }
1✔
630
                }()
631
                go func() {
2✔
632
                        if err := vca.restoreController.Run(vca.restoreControllerThreads, stop); err != nil {
2✔
633
                                log.Log.Warningf("error running the restore controller: %v", err)
1✔
634
                        }
1✔
635
                }()
636
                go func() {
2✔
637
                        if err := vca.exportController.Run(vca.exportControllerThreads, stop); err != nil {
2✔
638
                                log.Log.Warningf("error running the export controller: %v", err)
1✔
639
                        }
1✔
640
                }()
641
                go vca.workloadUpdateController.Run(stop)
1✔
642
                go vca.nodeTopologyUpdater.Run(vca.nodeTopologyUpdatePeriod, stop)
1✔
643
                go func() {
2✔
644
                        if err := vca.vmCloneController.Run(vca.cloneControllerThreads, stop); err != nil {
2✔
645
                                log.Log.Warningf("error running the clone controller: %v", err)
1✔
646
                        }
1✔
647
                }()
648
                go func() {
2✔
649
                        if err := vca.vmBackupController.Run(vca.backupControllerThreads, stop); err != nil {
2✔
650
                                log.Log.Warningf("error running the backup controller: %v", err)
1✔
651
                        }
1✔
652
                }()
653

654
                cache.WaitForCacheSync(stop, vca.persistentVolumeClaimInformer.HasSynced, vca.namespaceInformer.HasSynced, vca.resourceQuotaInformer.HasSynced)
1✔
655
                close(vca.readyChan)
1✔
656
                metrics.SetVirtControllerLeading()
1✔
657
        }
658
}
659

660
func (vca *VirtControllerApp) newRecorder(namespace string, componentName string) record.EventRecorder {
×
661
        eventBroadcaster := record.NewBroadcaster()
×
662
        eventBroadcaster.StartRecordingToSink(&k8coresv1.EventSinkImpl{Interface: vca.clientSet.CoreV1().Events(namespace)})
×
663
        return eventBroadcaster.NewRecorder(scheme.Scheme, k8sv1.EventSource{Component: componentName})
×
664
}
×
665

666
func (vca *VirtControllerApp) initCommon() {
×
667
        var err error
×
668

×
669
        virtClient, err := kubecli.GetKubevirtClient()
×
670
        if err != nil {
×
671
                golog.Fatal(err)
×
672
        }
×
673

674
        containerdisk.SetLocalDirectoryOnly(filepath.Join(vca.ephemeralDiskDir, "container-disk-data"))
×
675

×
676
        netAnnotationsGenerator := netannotations.NewGenerator(vca.clusterConfig)
×
677

×
678
        vca.templateService = services.NewTemplateService(vca.launcherImage,
×
679
                vca.launcherQemuTimeout,
×
680
                vca.virtShareDir,
×
681
                vca.ephemeralDiskDir,
×
682
                vca.containerDiskDir,
×
683
                vca.hotplugDiskDir,
×
684
                vca.imagePullSecret,
×
685
                vca.persistentVolumeClaimCache,
×
686
                virtClient,
×
687
                vca.clusterConfig,
×
688
                vca.launcherSubGid,
×
689
                vca.exporterImage,
×
690
                vca.resourceQuotaInformer.GetStore(),
×
691
                vca.namespaceStore,
×
692
                services.WithSidecarCreator(
×
693
                        func(vmi *v1.VirtualMachineInstance, _ *v1.KubeVirtConfiguration) (hooks.HookSidecarList, error) {
×
694
                                return hooks.UnmarshalHookSidecarList(vmi)
×
695
                        }),
×
696
                services.WithSidecarCreator(netbinding.NetBindingPluginSidecarList),
697
                services.WithNetBindingPluginMemoryCalculator(netbinding.MemoryCalculator{}),
698
                services.WithAnnotationsGenerators(netAnnotationsGenerator, storageannotations.Generator{}),
699
                services.WithNetTargetAnnotationsGenerator(netAnnotationsGenerator),
700
        )
701

702
        topologyHinter := topology.NewTopologyHinter(vca.nodeInformer.GetStore(), vca.vmiInformer.GetStore(), vca.clusterConfig)
×
703

×
704
        vca.vmiController, err = vmi.NewController(vca.templateService,
×
705
                vca.vmiInformer,
×
706
                vca.vmInformer,
×
707
                vca.kvPodInformer,
×
708
                vca.persistentVolumeClaimInformer,
×
709
                vca.migrationInformer,
×
710
                vca.storageClassInformer,
×
711
                vca.vmiRecorder,
×
712
                vca.clientSet,
×
713
                vca.dataVolumeInformer,
×
714
                vca.storageProfileInformer,
×
715
                vca.cdiInformer,
×
716
                vca.cdiConfigInformer,
×
717
                vca.clusterConfig,
×
718
                topologyHinter,
×
719
                netAnnotationsGenerator,
×
720
                netcontrollers.UpdateVMIStatus,
×
721
                func(field *k8sfield.Path, vmiSpec *v1.VirtualMachineInstanceSpec, clusterCfg *virtconfig.ClusterConfig) []metav1.StatusCause {
×
722
                        return netadmitter.ValidateCreation(field, vmiSpec, clusterCfg)
×
723
                },
×
724
                netmigration.NewEvaluator(),
725
                vca.additionalLauncherAnnotationsSync,
726
                vca.additionalLauncherLabelsSync,
727
        )
728
        if err != nil {
×
729
                panic(err)
×
730
        }
731

732
        if vca.isDRAEnabled {
×
733
                draStatusRecorder := vca.newRecorder(k8sv1.NamespaceAll, "dra-status-controller")
×
734
                vca.draStatusController, err = dra.NewDRAStatusController(
×
735
                        vca.clusterConfig,
×
736
                        vca.vmiInformer,
×
737
                        vca.kvPodInformer,
×
738
                        vca.resourceClaimInformer,
×
739
                        vca.resourceSliceInformer,
×
740
                        draStatusRecorder,
×
741
                        vca.clientSet,
×
742
                )
×
743
        }
×
744

745
        recorder := vca.newRecorder(k8sv1.NamespaceAll, "node-controller")
×
746
        vca.nodeController, err = node.NewController(vca.clientSet, vca.nodeInformer, vca.vmiInformer, recorder)
×
747
        if err != nil {
×
748
                panic(err)
×
749
        }
750
        // Adding a timeout to the clientSet of the migration controller, to avoid potential deadlocks
751
        clientSet, err := vca.clientSet.SetRestTimeout(migrationControllerRestTimeout)
×
752
        if err != nil {
×
753
                panic(err)
×
754
        }
755
        vca.migrationController, err = migration.NewController(
×
756
                vca.templateService,
×
757
                vca.vmiInformer,
×
758
                vca.kvPodInformer,
×
759
                vca.migrationInformer,
×
760
                vca.nodeInformer,
×
761
                vca.persistentVolumeClaimInformer,
×
762
                vca.storageClassInformer,
×
763
                vca.storageProfileInformer,
×
764
                vca.migrationPolicyInformer,
×
765
                vca.resourceQuotaInformer,
×
766
                vca.kubeVirtInformer,
×
767
                vca.vmiRecorder,
×
768
                clientSet,
×
769
                vca.clusterConfig,
×
770
                netAnnotationsGenerator,
×
771
        )
×
772
        if err != nil {
×
773
                panic(err)
×
774
        }
775

776
        vca.nodeTopologyUpdater = topology.NewNodeTopologyUpdater(vca.clientSet, topologyHinter, vca.nodeInformer)
×
777
}
778

779
func (vca *VirtControllerApp) initReplicaSet() {
×
780
        var err error
×
781
        recorder := vca.newRecorder(k8sv1.NamespaceAll, "virtualmachinereplicaset-controller")
×
782
        vca.rsController, err = replicaset.NewController(vca.vmiInformer, vca.rsInformer, recorder, vca.clientSet, controller.BurstReplicas)
×
783
        if err != nil {
×
784
                panic(err)
×
785
        }
786
}
787

788
func (vca *VirtControllerApp) initPool() {
×
789
        var err error
×
790
        recorder := vca.newRecorder(k8sv1.NamespaceAll, "virtualmachinepool-controller")
×
791
        vca.poolController, err = pool.NewController(vca.clientSet,
×
792
                vca.vmiInformer,
×
793
                vca.vmInformer,
×
794
                vca.poolInformer,
×
795
                vca.persistentVolumeClaimInformer,
×
796
                vca.dataVolumeInformer,
×
797
                vca.controllerRevisionInformer,
×
798
                recorder,
×
799
                controller.BurstReplicas)
×
800
        if err != nil {
×
801
                panic(err)
×
802
        }
803
}
804

805
func (vca *VirtControllerApp) initVirtualMachines() {
×
806
        var err error
×
807
        recorder := vca.newRecorder(k8sv1.NamespaceAll, "virtualmachine-controller")
×
808

×
809
        vca.vmController, err = vm.NewController(
×
810
                vca.vmiInformer,
×
811
                vca.vmInformer,
×
812
                vca.dataVolumeInformer,
×
813
                vca.dataSourceInformer,
×
814
                vca.kubeVirtInformer,
×
815
                vca.namespaceInformer,
×
816
                vca.persistentVolumeClaimInformer,
×
817
                vca.controllerRevisionInformer,
×
818
                recorder,
×
819
                vca.clientSet,
×
820
                vca.clusterConfig,
×
821
                netcontrollers.NewVMController(
×
822
                        vca.clientSet.GeneratedKubeVirtClient(),
×
823
                ),
×
824
                vm.NewFirmwareController(vca.clientSet.GeneratedKubeVirtClient()),
×
825
                instancetypecontroller.New(
×
826
                        vca.instancetypeInformer.GetStore(),
×
827
                        vca.clusterInstancetypeInformer.GetStore(),
×
828
                        vca.preferenceInformer.GetStore(),
×
829
                        vca.clusterPreferenceInformer.GetStore(),
×
830
                        vca.controllerRevisionInformer.GetStore(),
×
831
                        vca.clientSet,
×
832
                        vca.clusterConfig,
×
833
                        recorder,
×
834
                ),
×
835
                vca.additionalLauncherAnnotationsSync,
×
836
                vca.additionalLauncherLabelsSync,
×
837
        )
×
838
        if err != nil {
×
839
                panic(err)
×
840
        }
841
}
842

843
func (vca *VirtControllerApp) initDisruptionBudgetController() {
×
844
        var err error
×
845
        recorder := vca.newRecorder(k8sv1.NamespaceAll, "disruptionbudget-controller")
×
846
        vca.disruptionBudgetController, err = disruptionbudget.NewDisruptionBudgetController(
×
847
                vca.vmiInformer,
×
848
                vca.pdbInformer,
×
849
                vca.allPodInformer,
×
850
                vca.migrationInformer,
×
851
                recorder,
×
852
                vca.clientSet,
×
853
        )
×
854
        if err != nil {
×
855
                panic(err)
×
856
        }
857
}
858

859
func (vca *VirtControllerApp) initWorkloadUpdaterController() {
×
860
        var err error
×
861
        recorder := vca.newRecorder(k8sv1.NamespaceAll, "workload-update-controller")
×
862
        vca.workloadUpdateController, err = workloadupdater.NewWorkloadUpdateController(
×
863
                vca.launcherImage,
×
864
                vca.vmiInformer,
×
865
                vca.kvPodInformer,
×
866
                vca.migrationInformer,
×
867
                vca.kubeVirtInformer,
×
868
                recorder,
×
869
                vca.clientSet,
×
870
                vca.clusterConfig)
×
871
        if err != nil {
×
872
                panic(err)
×
873
        }
874
}
875

876
func (vca *VirtControllerApp) initEvacuationController() {
×
877
        var err error
×
878
        recorder := vca.newRecorder(k8sv1.NamespaceAll, "evacuation-controller")
×
879
        vca.evacuationController, err = evacuation.NewEvacuationController(
×
880
                vca.vmiInformer,
×
881
                vca.migrationInformer,
×
882
                vca.nodeInformer,
×
883
                vca.kvPodInformer,
×
884
                recorder,
×
885
                vca.clientSet,
×
886
                vca.clusterConfig,
×
887
        )
×
888
        if err != nil {
×
889
                panic(err)
×
890
        }
891
}
892

893
func (vca *VirtControllerApp) initSnapshotController() {
×
894
        recorder := vca.newRecorder(k8sv1.NamespaceAll, "snapshot-controller")
×
895
        vca.snapshotController = &snapshot.VMSnapshotController{
×
896
                Client:                    vca.clientSet,
×
897
                VMSnapshotInformer:        vca.vmSnapshotInformer,
×
898
                VMSnapshotContentInformer: vca.vmSnapshotContentInformer,
×
899
                VMInformer:                vca.vmInformer,
×
900
                VMIInformer:               vca.vmiInformer,
×
901
                StorageClassInformer:      vca.storageClassInformer,
×
902
                StorageProfileInformer:    vca.storageProfileInformer,
×
903
                PVCInformer:               vca.persistentVolumeClaimInformer,
×
904
                CRDInformer:               vca.crdInformer,
×
905
                PodInformer:               vca.allPodInformer,
×
906
                DVInformer:                vca.dataVolumeInformer,
×
907
                CRInformer:                vca.controllerRevisionInformer,
×
908
                Recorder:                  recorder,
×
909
                ResyncPeriod:              vca.snapshotControllerResyncPeriod,
×
910
        }
×
911
        if err := vca.snapshotController.Init(); err != nil {
×
912
                panic(err)
×
913
        }
914
}
915

916
func (vca *VirtControllerApp) initRestoreController() {
×
917
        recorder := vca.newRecorder(k8sv1.NamespaceAll, "restore-controller")
×
918
        vca.restoreController = &snapshot.VMRestoreController{
×
919
                Client:                    vca.clientSet,
×
920
                VMRestoreInformer:         vca.vmRestoreInformer,
×
921
                VMSnapshotInformer:        vca.vmSnapshotInformer,
×
922
                VMSnapshotContentInformer: vca.vmSnapshotContentInformer,
×
923
                VMInformer:                vca.vmInformer,
×
924
                VMIInformer:               vca.vmiInformer,
×
925
                DataVolumeInformer:        vca.dataVolumeInformer,
×
926
                PVCInformer:               vca.persistentVolumeClaimInformer,
×
927
                StorageClassInformer:      vca.storageClassInformer,
×
928
                VolumeSnapshotProvider:    vca.snapshotController,
×
929
                Recorder:                  recorder,
×
930
                CRInformer:                vca.controllerRevisionInformer,
×
931
        }
×
932
        if err := vca.restoreController.Init(); err != nil {
×
933
                panic(err)
×
934
        }
935
}
936

937
func (vca *VirtControllerApp) initExportController() {
×
938
        recorder := vca.newRecorder(k8sv1.NamespaceAll, "export-controller")
×
939
        vca.exportController = &export.VMExportController{
×
940
                ManifestRenderer:            vca.templateService,
×
941
                Client:                      vca.clientSet,
×
942
                VMExportInformer:            vca.vmExportInformer,
×
943
                PVCInformer:                 vca.persistentVolumeClaimInformer,
×
944
                PodInformer:                 vca.allPodInformer,
×
945
                DataVolumeInformer:          vca.dataVolumeInformer,
×
946
                ServiceInformer:             vca.exportServiceInformer,
×
947
                Recorder:                    recorder,
×
948
                ConfigMapInformer:           vca.caExportConfigMapInformer,
×
949
                IngressCache:                vca.ingressCache,
×
950
                RouteCache:                  vca.routeCache,
×
951
                KubevirtNamespace:           vca.kubevirtNamespace,
×
952
                RouteConfigMapInformer:      vca.exportRouteConfigMapInformer,
×
953
                SecretInformer:              vca.unmanagedSecretInformer,
×
954
                VolumeSnapshotProvider:      vca.snapshotController,
×
955
                VMSnapshotInformer:          vca.vmSnapshotInformer,
×
956
                VMSnapshotContentInformer:   vca.vmSnapshotContentInformer,
×
957
                VMInformer:                  vca.vmInformer,
×
958
                VMIInformer:                 vca.vmiInformer,
×
959
                CRDInformer:                 vca.crdInformer,
×
960
                KubeVirtInformer:            vca.kubeVirtInformer,
×
961
                InstancetypeInformer:        vca.instancetypeInformer,
×
962
                ClusterInstancetypeInformer: vca.clusterInstancetypeInformer,
×
963
                PreferenceInformer:          vca.preferenceInformer,
×
964
                ClusterPreferenceInformer:   vca.clusterPreferenceInformer,
×
965
                ControllerRevisionInformer:  vca.controllerRevisionInformer,
×
966
        }
×
967
        if err := vca.exportController.Init(); err != nil {
×
968
                panic(err)
×
969
        }
970
}
971

972
func (vca *VirtControllerApp) initCloneController() {
×
973
        var err error
×
974
        recorder := vca.newRecorder(k8sv1.NamespaceAll, "clone-controller")
×
975
        vca.vmCloneController, err = clonecontroller.NewVmCloneController(
×
976
                vca.clientSet, vca.vmCloneInformer, vca.vmSnapshotInformer, vca.vmRestoreInformer, vca.vmInformer, vca.vmSnapshotContentInformer, vca.persistentVolumeClaimInformer, recorder,
×
977
        )
×
978
        if err != nil {
×
979
                panic(err)
×
980
        }
981
}
982

NEW
983
func (vca *VirtControllerApp) initBackupController() {
×
NEW
984
        var err error
×
NEW
985
        recorder := vca.newRecorder(k8sv1.NamespaceAll, "backup-controller")
×
NEW
986
        vca.vmBackupController, err = backup.NewVMBackupController(
×
NEW
987
                vca.clientSet, vca.vmBackupInformer, vca.vmInformer, vca.vmiInformer, vca.persistentVolumeClaimInformer, recorder,
×
NEW
988
        )
×
NEW
989
        if err != nil {
×
NEW
990
                panic(err)
×
991
        }
992
}
993

994
func (vca *VirtControllerApp) leaderProbe(_ *restful.Request, response *restful.Response) {
2✔
995
        res := map[string]interface{}{}
2✔
996

2✔
997
        select {
2✔
998
        case _, opened := <-vca.readyChan:
1✔
999
                if !opened {
2✔
1000
                        res["apiserver"] = map[string]interface{}{"leader": "true"}
1✔
1001
                        if err := response.WriteHeaderAndJson(http.StatusOK, res, restful.MIME_JSON); err != nil {
1✔
1002
                                log.Log.Warningf("failed to return 200 OK reply: %v", err)
×
1003
                        }
×
1004
                        return
1✔
1005
                }
1006
        default:
1✔
1007
        }
1008
        res["apiserver"] = map[string]interface{}{"leader": "false"}
1✔
1009
        if err := response.WriteHeaderAndJson(http.StatusOK, res, restful.MIME_JSON); err != nil {
1✔
1010
                log.Log.Warningf("failed to return 200 OK reply: %v", err)
×
1011
        }
×
1012
}
1013

1014
func (vca *VirtControllerApp) AddFlags() {
×
1015
        vca.InitFlags()
×
1016

×
1017
        leaderelectionconfig.BindFlags(&vca.LeaderElection)
×
1018

×
1019
        vca.BindAddress = defaultHost
×
1020
        vca.Port = defaultPort
×
1021

×
1022
        vca.AddCommonFlags()
×
1023

×
1024
        flag.StringVar(&vca.launcherImage, "launcher-image", launcherImage,
×
1025
                "Shim container for containerized VMIs")
×
1026

×
1027
        flag.StringVar(&vca.exporterImage, "exporter-image", exporterImage,
×
1028
                "Container for exporting VMs and VM images")
×
1029

×
1030
        flag.IntVar(&vca.launcherQemuTimeout, "launcher-qemu-timeout", launcherQemuTimeout,
×
1031
                "Amount of time to wait for qemu")
×
1032

×
1033
        flag.StringVar(&vca.imagePullSecret, "image-pull-secret", imagePullSecret,
×
1034
                "Secret to use for pulling virt-launcher and/or registry disks")
×
1035

×
1036
        flag.StringVar(&vca.virtShareDir, "kubevirt-share-dir", util.VirtShareDir,
×
1037
                "Shared directory between virt-handler and virt-launcher")
×
1038

×
1039
        flag.StringVar(&vca.ephemeralDiskDir, "ephemeral-disk-dir", ephemeralDiskDir,
×
1040
                "Base directory for ephemeral disk data")
×
1041

×
1042
        flag.StringVar(&vca.containerDiskDir, "container-disk-dir", containerDiskDir,
×
1043
                "Base directory for container disk data")
×
1044

×
1045
        flag.StringVar(&vca.hotplugDiskDir, "hotplug-disk-dir", hotplugDiskDir,
×
1046
                "Base directory for hotplug disk data")
×
1047

×
1048
        // allows user-defined threads based on the underlying hardware in use
×
1049
        flag.IntVar(&vca.nodeControllerThreads, "node-controller-threads", defaultControllerThreads,
×
1050
                "Number of goroutines to run for node controller")
×
1051

×
1052
        flag.IntVar(&vca.vmiControllerThreads, "vmi-controller-threads", defaultVMIControllerThreads,
×
1053
                "Number of goroutines to run for vmi controller")
×
1054

×
1055
        flag.IntVar(&vca.draStatusControllerThreads, "dra-status-controller-threads", defaultControllerThreads,
×
1056
                "Number of goroutines to run for dra status controller")
×
1057

×
1058
        flag.IntVar(&vca.rsControllerThreads, "rs-controller-threads", defaultControllerThreads,
×
1059
                "Number of goroutines to run for replicaset controller")
×
1060

×
1061
        flag.IntVar(&vca.poolControllerThreads, "pool-controller-threads", defaultControllerThreads,
×
1062
                "Number of goroutines to run for pool controller")
×
1063

×
1064
        flag.IntVar(&vca.vmControllerThreads, "vm-controller-threads", defaultControllerThreads,
×
1065
                "Number of goroutines to run for vm controller")
×
1066

×
1067
        flag.IntVar(&vca.migrationControllerThreads, "migration-controller-threads", defaultControllerThreads,
×
1068
                "Number of goroutines to run for migration controller")
×
1069

×
1070
        flag.IntVar(&vca.evacuationControllerThreads, "evacuation-controller-threads", defaultControllerThreads,
×
1071
                "Number of goroutines to run for evacuation controller")
×
1072

×
1073
        flag.IntVar(&vca.disruptionBudgetControllerThreads, "disruption-budget-controller-threads", defaultControllerThreads,
×
1074
                "Number of goroutines to run for disruption budget controller")
×
1075

×
1076
        flag.Int64Var(&vca.launcherSubGid, "launcher-subgid", defaultLauncherSubGid,
×
1077
                "ID of subgroup to virt-launcher")
×
1078

×
1079
        flag.IntVar(&vca.snapshotControllerThreads, "snapshot-controller-threads", defaultSnapshotControllerThreads,
×
1080
                "Number of goroutines to run for snapshot controller")
×
1081

×
1082
        flag.IntVar(&vca.restoreControllerThreads, "restore-controller-threads", defaultControllerThreads,
×
1083
                "Number of goroutines to run for restore controller")
×
1084

×
1085
        flag.IntVar(&vca.exportControllerThreads, "export-controller-threads", defaultControllerThreads,
×
1086
                "Number of goroutines to run for virtual machine export controller")
×
1087

×
1088
        flag.DurationVar(&vca.snapshotControllerResyncPeriod, "snapshot-controller-resync-period", defaultSnapshotControllerResyncPeriod,
×
1089
                "Number of goroutines to run for snapshot controller")
×
1090

×
1091
        flag.DurationVar(&vca.nodeTopologyUpdatePeriod, "node-topology-update-period", defaultNodeTopologyUpdatePeriod,
×
1092
                "Update period for the node topology updater")
×
1093

×
1094
        flag.StringVar(&vca.promCertFilePath, "prom-cert-file", defaultPromCertFilePath,
×
1095
                "Client certificate used to prove the identity of the virt-controller when it must call out Promethus during a request")
×
1096

×
1097
        flag.StringVar(&vca.promKeyFilePath, "prom-key-file", defaultPromKeyFilePath,
×
1098
                "Private key for the client certificate used to prove the identity of the virt-controller when it must call out Promethus during a request")
×
1099

×
1100
        flag.IntVar(&vca.cloneControllerThreads, "clone-controller-threads", defaultControllerThreads,
×
1101
                "Number of goroutines to run for clone controller")
×
1102

×
1103
        flag.StringSliceVar(&vca.additionalLauncherAnnotationsSync, "additional-launcher-annotations-sync", []string{},
×
1104
                "Comma separated list of annotation keys which if present on the VM template and so VMI, will be sync to the virt-launcher pod. Note, it is unidirectional from VM.spec.template.metadata -> VMI and VMI -> virt-launcher pod")
×
1105

×
1106
        flag.StringSliceVar(&vca.additionalLauncherLabelsSync, "additional-launcher-labels-sync", []string{},
×
1107
                "Comma separated list of labels keys which if present on the VM template and so VMI, will be sync to the virt-launcher pod. Note, it is unidirectional from VM.spec.template.metadata -> VMI and VMI -> virt-launcher pod")
×
NEW
1108

×
NEW
1109
        flag.IntVar(&vca.backupControllerThreads, "backup-controller-threads", defaultBackupControllerThreads,
×
NEW
1110
                "Number of goroutines to run for backup controller")
×
UNCOV
1111
}
×
1112

1113
func (vca *VirtControllerApp) setupLeaderElector() (err error) {
×
1114
        clientConfig, err := kubecli.GetKubevirtClientConfig()
×
1115
        if err != nil {
×
1116
                return
×
1117
        }
×
1118

1119
        clientConfig.RateLimiter =
×
1120
                flowcontrol.NewTokenBucketRateLimiter(
×
1121
                        virtconfig.DefaultVirtControllerQPS,
×
1122
                        virtconfig.DefaultVirtControllerBurst)
×
1123

×
1124
        clientSet, err := kubecli.GetKubevirtClientFromRESTConfig(clientConfig)
×
1125
        if err != nil {
×
1126
                return
×
1127
        }
×
1128

1129
        rl, err := resourcelock.New(vca.LeaderElection.ResourceLock,
×
1130
                vca.kubevirtNamespace,
×
1131
                leaderelectionconfig.DefaultLeaseName,
×
1132
                clientSet.CoreV1(),
×
1133
                clientSet.CoordinationV1(),
×
1134
                resourcelock.ResourceLockConfig{
×
1135
                        Identity:      vca.host,
×
1136
                        EventRecorder: vca.newRecorder(k8sv1.NamespaceAll, leaderelectionconfig.DefaultLeaseName),
×
1137
                })
×
1138

×
1139
        if err != nil {
×
1140
                return
×
1141
        }
×
1142

1143
        vca.leaderElector, err = leaderelection.NewLeaderElector(
×
1144
                leaderelection.LeaderElectionConfig{
×
1145
                        Lock:          rl,
×
1146
                        LeaseDuration: vca.LeaderElection.LeaseDuration.Duration,
×
1147
                        RenewDeadline: vca.LeaderElection.RenewDeadline.Duration,
×
1148
                        RetryPeriod:   vca.LeaderElection.RetryPeriod.Duration,
×
1149
                        Callbacks: leaderelection.LeaderCallbacks{
×
1150
                                OnStartedLeading: vca.onStartedLeading(),
×
1151
                                OnStoppedLeading: func() {
×
1152
                                        golog.Fatal("leaderelection lost")
×
1153
                                },
×
1154
                        },
1155
                })
1156

1157
        return
×
1158
}
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