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

kubevirt / kubevirt / d5c3eabe-b8e1-4666-858c-9a77f2bca263

02 Jun 2026 06:30PM UTC coverage: 71.653% (+0.04%) from 71.609%
d5c3eabe-b8e1-4666-858c-9a77f2bca263

push

prow

web-flow
Merge pull request #17661 from oshoval/vep183

VEP183: Add DRA-backed network devices (alpha)

217 of 222 new or added lines in 13 files covered. (97.75%)

10 existing lines in 4 files now uncovered.

78633 of 109742 relevant lines covered (71.65%)

619.74 hits per line

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

11.3
/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/util/ratelimiter"
66

67
        "kubevirt.io/kubevirt/pkg/virt-controller/watch/topology"
68

69
        "kubevirt.io/kubevirt/pkg/healthz"
70
        "kubevirt.io/kubevirt/pkg/monitoring/profiler"
71

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

80
        "kubevirt.io/kubevirt/pkg/certificates/bootstrap"
81
        "kubevirt.io/kubevirt/pkg/controller"
82
        netresources "kubevirt.io/kubevirt/pkg/network/resources"
83
        clusterutil "kubevirt.io/kubevirt/pkg/util/cluster"
84

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

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

108
const (
109
        defaultPort = 8182
110

111
        defaultHost = "0.0.0.0"
112

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

117
        migrationControllerRestTimeout = 30 * time.Second
118

119
        imagePullSecret = ""
120

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

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

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

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

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

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

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

145
type VirtControllerApp struct {
146
        service.ServiceListen
147

148
        clientSet       kubecli.KubevirtClient
149
        templateService *services.TemplateService
150
        restClient      *clientrest.RESTClient
151
        informerFactory controller.KubeInformerFactory
152
        kvPodInformer   cache.SharedIndexInformer
153

154
        nodeInformer   cache.SharedIndexInformer
155
        nodeController *node.Controller
156

157
        vmiCache      cache.Store
158
        vmiController *vmi.Controller
159
        vmiInformer   cache.SharedIndexInformer
160
        vmiRecorder   record.EventRecorder
161

162
        namespaceInformer cache.SharedIndexInformer
163
        namespaceStore    cache.Store
164

165
        kubeVirtInformer cache.SharedIndexInformer
166

167
        clusterConfig *virtconfig.ClusterConfig
168

169
        pdbInformer cache.SharedIndexInformer
170

171
        persistentVolumeClaimCache    cache.Store
172
        persistentVolumeClaimInformer cache.SharedIndexInformer
173

174
        rsController *replicaset.Controller
175
        rsInformer   cache.SharedIndexInformer
176

177
        poolController *pool.Controller
178
        poolInformer   cache.SharedIndexInformer
179

180
        vmController *vm.Controller
181
        vmInformer   cache.SharedIndexInformer
182

183
        controllerRevisionInformer cache.SharedIndexInformer
184

185
        dataVolumeInformer     cache.SharedIndexInformer
186
        dataSourceInformer     cache.SharedIndexInformer
187
        storageProfileInformer cache.SharedIndexInformer
188
        cdiInformer            cache.SharedIndexInformer
189
        cdiConfigInformer      cache.SharedIndexInformer
190

191
        migrationController *migration.Controller
192
        migrationInformer   cache.SharedIndexInformer
193

194
        workloadUpdateController *workloadupdater.WorkloadUpdateController
195

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

214
        crdInformer cache.SharedIndexInformer
215

216
        migrationPolicyInformer cache.SharedIndexInformer
217

218
        vmCloneInformer   cache.SharedIndexInformer
219
        vmCloneController *clonecontroller.VMCloneController
220

221
        vmBackupInformer        cache.SharedIndexInformer
222
        vmBackupTrackerInformer cache.SharedIndexInformer
223
        vmBackupController      *backup.VMBackupController
224

225
        instancetypeInformer        cache.SharedIndexInformer
226
        clusterInstancetypeInformer cache.SharedIndexInformer
227
        preferenceInformer          cache.SharedIndexInformer
228
        clusterPreferenceInformer   cache.SharedIndexInformer
229

230
        LeaderElection leaderelectionconfig.Configuration
231

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

246
        ctx context.Context
247

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

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

274
        promCertFilePath string
275
        promKeyFilePath  string
276

277
        nodeTopologyUpdater      topology.NodeTopologyUpdater
278
        nodeTopologyUpdatePeriod time.Duration
279
        reloadableRateLimiter    *ratelimiter.ReloadableRateLimiter
280
        leaderElector            *leaderelection.LeaderElector
281

282
        onOpenshift bool
283
}
284

285
var _ service.Service = &VirtControllerApp{}
286

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

296
func Execute() {
×
297
        var err error
×
298
        var app = VirtControllerApp{}
×
299

×
300
        app.LeaderElection = leaderelectionconfig.DefaultLeaderElectionConfiguration()
×
301

×
302
        service.Setup(&app)
×
303

×
304
        app.readyChan = make(chan bool, 1)
×
305

×
306
        log.InitializeLogging("virt-controller")
×
307

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

320
        app.restClient = app.clientSet.RestClient()
×
321

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

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

×
334
        ctx, cancel := context.WithCancel(context.Background())
×
335
        stopChan := ctx.Done()
×
336
        app.ctx = ctx
×
337

×
338
        app.informerFactory = controller.NewKubeInformerFactory(app.restClient, app.clientSet, nil, app.kubevirtNamespace)
×
339

×
340
        app.crdInformer = app.informerFactory.CRD()
×
341
        app.kubeVirtInformer = app.informerFactory.KubeVirt()
×
342

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

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

357
        app.reInitChan = make(chan string, 10)
×
358
        app.hasCDI = app.clusterConfig.HasDataVolumeAPI()
×
NEW
359
        app.isDRAEnabled = app.clusterConfig.AnyDeviceDRAGateEnabled()
×
360
        app.clusterConfig.SetConfigModifiedCallback(app.configModificationCallback)
×
361
        app.clusterConfig.SetConfigModifiedCallback(app.shouldChangeLogVerbosity)
×
362
        app.clusterConfig.SetConfigModifiedCallback(app.shouldChangeRateLimiter)
×
363

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

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

×
374
        restful.Add(webService)
×
375

×
376
        app.vmiInformer = app.informerFactory.VMI()
×
377
        app.kvPodInformer = app.informerFactory.KubeVirtPod()
×
378
        app.nodeInformer = app.informerFactory.KubeVirtNode()
×
379
        app.namespaceStore = app.informerFactory.Namespace().GetStore()
×
380
        app.namespaceInformer = app.informerFactory.Namespace()
×
381
        app.vmiCache = app.vmiInformer.GetStore()
×
382
        app.vmiRecorder = app.newRecorder(k8sv1.NamespaceAll, "virtualmachine-controller")
×
383

×
384
        app.rsInformer = app.informerFactory.VMIReplicaSet()
×
385
        app.poolInformer = app.informerFactory.VMPool()
×
386

×
387
        app.persistentVolumeClaimInformer = app.informerFactory.PersistentVolumeClaim()
×
388
        app.persistentVolumeClaimCache = app.persistentVolumeClaimInformer.GetStore()
×
389

×
390
        app.pdbInformer = app.informerFactory.K8SInformerFactory().Policy().V1().PodDisruptionBudgets().Informer()
×
391

×
392
        app.vmInformer = app.informerFactory.VirtualMachine()
×
393

×
394
        app.migrationInformer = app.informerFactory.VirtualMachineInstanceMigration()
×
395

×
396
        app.controllerRevisionInformer = app.informerFactory.ControllerRevision()
×
397

×
398
        app.vmBackupInformer = app.informerFactory.VirtualMachineBackup()
×
399
        app.vmBackupTrackerInformer = app.informerFactory.VirtualMachineBackupTracker()
×
400
        app.vmExportInformer = app.informerFactory.VirtualMachineExport()
×
401
        app.vmSnapshotInformer = app.informerFactory.VirtualMachineSnapshot()
×
402
        app.vmSnapshotContentInformer = app.informerFactory.VirtualMachineSnapshotContent()
×
403
        app.vmRestoreInformer = app.informerFactory.VirtualMachineRestore()
×
404
        app.storageClassInformer = app.informerFactory.StorageClass()
×
405
        app.caExportConfigMapInformer = app.informerFactory.KubeVirtExportCAConfigMap()
×
406
        app.caBackupConfigMapInformer = app.informerFactory.KubeVirtBackupCAConfigMap()
×
407
        app.exportRouteConfigMapInformer = app.informerFactory.ExportRouteConfigMap()
×
408
        app.unmanagedSecretInformer = app.informerFactory.UnmanagedSecrets()
×
409
        app.allPodInformer = app.informerFactory.Pod()
×
410
        app.exportServiceInformer = app.informerFactory.ExportService()
×
411
        app.resourceQuotaInformer = app.informerFactory.ResourceQuota()
×
412

×
413
        if app.hasCDI {
×
414
                app.dataVolumeInformer = app.informerFactory.DataVolume()
×
415
                app.cdiInformer = app.informerFactory.CDI()
×
416
                app.cdiConfigInformer = app.informerFactory.CDIConfig()
×
417
                app.dataSourceInformer = app.informerFactory.DataSource()
×
418
                app.storageProfileInformer = app.informerFactory.StorageProfile()
×
419
                log.Log.Infof("CDI detected, DataVolume integration enabled")
×
420
        } else {
×
421
                // Add a dummy DataVolume informer in the event datavolume support
×
422
                // is disabled. This lets the controller continue to work without
×
423
                // requiring a separate branching code path.
×
424
                app.dataVolumeInformer = app.informerFactory.DummyDataVolume()
×
425
                app.cdiInformer = app.informerFactory.DummyCDI()
×
426
                app.cdiConfigInformer = app.informerFactory.DummyCDIConfig()
×
427
                app.dataSourceInformer = app.informerFactory.DummyDataSource()
×
428
                app.storageProfileInformer = app.informerFactory.DummyStorageProfile()
×
429
                log.Log.Infof("CDI not detected, DataVolume integration disabled")
×
430
        }
×
431

432
        onOpenShift, err := clusterutil.IsOnOpenShift(app.clientSet)
×
433
        if err != nil {
×
434
                golog.Fatalf("Error determining cluster type: %v", err)
×
435
        }
×
436
        if onOpenShift {
×
437
                log.Log.Info("we are on openshift")
×
438
                app.routeCache = app.informerFactory.OperatorRoute().GetStore()
×
439
        } else {
×
440
                log.Log.Info("we are on kubernetes")
×
441
                app.routeCache = app.informerFactory.DummyOperatorRoute().GetStore()
×
442
        }
×
443
        app.ingressCache = app.informerFactory.Ingress().GetStore()
×
444
        app.migrationPolicyInformer = app.informerFactory.MigrationPolicy()
×
445

×
446
        app.vmCloneInformer = app.informerFactory.VirtualMachineClone()
×
447

×
448
        app.instancetypeInformer = app.informerFactory.VirtualMachineInstancetype()
×
449
        app.clusterInstancetypeInformer = app.informerFactory.VirtualMachineClusterInstancetype()
×
450
        app.preferenceInformer = app.informerFactory.VirtualMachinePreference()
×
451
        app.clusterPreferenceInformer = app.informerFactory.VirtualMachineClusterPreference()
×
452

×
453
        app.onOpenshift = onOpenShift
×
454

×
455
        metricsInformers := &metrics.Indexers{
×
456
                VMIMigration: app.migrationInformer.GetIndexer(),
×
457
                KVPod:        app.kvPodInformer.GetIndexer(),
×
458
        }
×
459

×
460
        metricsStores := &metrics.Stores{
×
461
                VM:                    app.vmInformer.GetStore(),
×
462
                VMI:                   app.vmiInformer.GetStore(),
×
463
                PersistentVolumeClaim: app.persistentVolumeClaimInformer.GetStore(),
×
464
                Instancetype:          app.instancetypeInformer.GetStore(),
×
465
                ClusterInstancetype:   app.clusterInstancetypeInformer.GetStore(),
×
466
                Preference:            app.preferenceInformer.GetStore(),
×
467
                ClusterPreference:     app.clusterPreferenceInformer.GetStore(),
×
468
                ControllerRevision:    app.controllerRevisionInformer.GetStore(),
×
469
        }
×
470

×
471
        if err := metrics.SetupMetrics(
×
472
                metricsInformers,
×
473
                metricsStores,
×
474
                app.clusterConfig,
×
475
                app.clientSet,
×
476
        ); err != nil {
×
477
                golog.Fatal(err)
×
478
        }
×
479

480
        app.initCommon()
×
481
        app.initReplicaSet()
×
482
        app.initPool()
×
483
        app.initVirtualMachines()
×
484
        app.initDisruptionBudgetController()
×
485
        app.initEvacuationController()
×
486
        app.initSnapshotController()
×
487
        app.initRestoreController()
×
488
        app.initExportController()
×
489
        app.initWorkloadUpdaterController()
×
490
        app.initCloneController()
×
491
        app.initBackupController()
×
492
        go app.Run()
×
493

×
494
        <-app.reInitChan
×
495
        cancel()
×
496
}
497

498
// Detects if a config has been applied that requires
499
// re-initializing virt-controller.
500
func (vca *VirtControllerApp) configModificationCallback() {
4✔
501
        newHasCDI := vca.clusterConfig.HasDataVolumeAPI()
4✔
502
        if newHasCDI != vca.hasCDI {
6✔
503
                if newHasCDI {
3✔
504
                        log.Log.Infof("Reinitialize virt-controller, cdi api has been introduced")
1✔
505
                } else {
2✔
506
                        log.Log.Infof("Reinitialize virt-controller, cdi api has been removed")
1✔
507
                }
1✔
508
                vca.reInitChan <- "reinit"
2✔
509
                return
2✔
510
        }
511
        newIsDRAEnabled := vca.clusterConfig.AnyDeviceDRAGateEnabled()
2✔
512
        if newIsDRAEnabled != vca.isDRAEnabled {
2✔
513
                if newIsDRAEnabled {
×
514
                        log.Log.Infof("Reinitialize virt-controller, DRA integration has been introduced")
×
515
                } else {
×
516
                        log.Log.Infof("Reinitialize virt-controller, DRA integration has been removed")
×
517
                }
×
518
                vca.reInitChan <- "reinit"
×
519
                return
×
520
        }
521
}
522

523
// Update virt-controller rate limiter
524
func (vca *VirtControllerApp) shouldChangeRateLimiter() {
×
525
        config := vca.clusterConfig.GetConfig()
×
526
        qps := config.ControllerConfiguration.RestClient.RateLimiter.TokenBucketRateLimiter.QPS
×
527
        burst := config.ControllerConfiguration.RestClient.RateLimiter.TokenBucketRateLimiter.Burst
×
528
        vca.reloadableRateLimiter.Set(flowcontrol.NewTokenBucketRateLimiter(qps, burst))
×
529
        log.Log.V(2).Infof("setting rate limiter to %v QPS and %v Burst", qps, burst)
×
530
}
×
531

532
// Update virt-controller log verbosity on relevant config changes
533
func (vca *VirtControllerApp) shouldChangeLogVerbosity() {
×
534
        verbosity := vca.clusterConfig.GetVirtControllerVerbosity(vca.host)
×
535
        if err := log.Log.SetVerbosityLevel(int(verbosity)); err != nil {
×
536
                log.Log.Warningf("failed up update log verbosity to %d: %v", verbosity, err)
×
537
        } else {
×
538
                log.Log.V(2).Infof("set log verbosity to %d", verbosity)
×
539
        }
×
540
}
541

542
func (vca *VirtControllerApp) Run() {
×
543
        logger := log.Log
×
544

×
545
        promCertManager := bootstrap.NewFileCertificateManager(vca.promCertFilePath, vca.promKeyFilePath)
×
546
        go promCertManager.Start()
×
547
        promTLSConfig := kvtls.SetupPromTLS(promCertManager, vca.clusterConfig)
×
548

×
549
        go func() {
×
550
                httpLogger := logger.With("service", "http")
×
551
                _ = httpLogger.Level(log.INFO).Log("action", "listening", "interface", vca.BindAddress, "port", vca.Port)
×
552
                http.Handle("/metrics", promhttp.Handler())
×
553
                server := http.Server{
×
554
                        Addr:      vca.Address(),
×
555
                        Handler:   http.DefaultServeMux,
×
556
                        TLSConfig: promTLSConfig,
×
557
                        // Disable HTTP/2
×
558
                        // See CVE-2023-44487
×
559
                        TLSNextProto: map[string]func(*http.Server, *tls.Conn, http.Handler){},
×
560
                }
×
561
                if err := server.ListenAndServeTLS("", ""); err != nil {
×
562
                        golog.Fatal(err)
×
563
                }
×
564
        }()
565

566
        if err := vca.setupLeaderElector(); err != nil {
×
567
                golog.Fatal(err)
×
568
        }
×
569

570
        metrics.SetVirtControllerReady()
×
571
        vca.leaderElector.Run(vca.ctx)
×
572
        metrics.SetVirtControllerNotReady()
×
573
        panic("unreachable")
×
574
}
575

576
func (vca *VirtControllerApp) onStartedLeading() func(ctx context.Context) {
1✔
577
        return func(ctx context.Context) {
2✔
578
                stop := ctx.Done()
1✔
579
                vca.informerFactory.Start(stop)
1✔
580

1✔
581
                golog.Printf("STARTING controllers with following threads : "+
1✔
582
                        "node %d, vmi %d, replicaset %d, vm %d, migration %d, evacuation %d, disruptionBudget %d",
1✔
583
                        vca.nodeControllerThreads, vca.vmiControllerThreads, vca.rsControllerThreads,
1✔
584
                        vca.vmControllerThreads, vca.migrationControllerThreads, vca.evacuationControllerThreads,
1✔
585
                        vca.disruptionBudgetControllerThreads)
1✔
586

1✔
587
                if err := metrics.RegisterLeaderMetrics(); err != nil {
1✔
588
                        golog.Fatalf("failed to register leader metrics: %v", err)
×
589
                }
×
590

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

595
                if vca.migrationInformer == nil {
2✔
596
                        vca.migrationInformer = vca.informerFactory.VirtualMachineInstanceMigration()
1✔
597
                        metrics.UpdateVMIMigrationInformer(vca.migrationInformer.GetIndexer())
1✔
598
                }
1✔
599
                golog.Printf("\nvca.migrationInformer :%v\n", vca.migrationInformer)
1✔
600

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

605
                go vca.evacuationController.Run(vca.evacuationControllerThreads, stop)
1✔
606
                go vca.disruptionBudgetController.Run(vca.disruptionBudgetControllerThreads, stop)
1✔
607
                go vca.nodeController.Run(vca.nodeControllerThreads, stop)
1✔
608
                go vca.vmiController.Run(vca.vmiControllerThreads, stop)
1✔
609
                go vca.rsController.Run(vca.rsControllerThreads, stop)
1✔
610
                go vca.poolController.Run(vca.poolControllerThreads, stop)
1✔
611
                go vca.vmController.Run(vca.vmControllerThreads, stop)
1✔
612
                go vca.migrationController.Run(vca.migrationControllerThreads, stop)
1✔
613
                go func() {
2✔
614
                        if err := vca.snapshotController.Run(vca.snapshotControllerThreads, stop); err != nil {
2✔
615
                                log.Log.Warningf("error running the snapshot controller: %v", err)
1✔
616
                        }
1✔
617
                }()
618
                go func() {
2✔
619
                        if err := vca.restoreController.Run(vca.restoreControllerThreads, stop); err != nil {
2✔
620
                                log.Log.Warningf("error running the restore controller: %v", err)
1✔
621
                        }
1✔
622
                }()
623
                go func() {
2✔
624
                        if err := vca.exportController.Run(vca.exportControllerThreads, stop); err != nil {
2✔
625
                                log.Log.Warningf("error running the export controller: %v", err)
1✔
626
                        }
1✔
627
                }()
628
                go vca.workloadUpdateController.Run(stop)
1✔
629
                go vca.nodeTopologyUpdater.Run(vca.nodeTopologyUpdatePeriod, stop)
1✔
630
                go func() {
2✔
631
                        if err := vca.vmCloneController.Run(vca.cloneControllerThreads, stop); err != nil {
2✔
632
                                log.Log.Warningf("error running the clone controller: %v", err)
1✔
633
                        }
1✔
634
                }()
635
                go func() {
2✔
636
                        if err := vca.vmBackupController.Run(vca.backupControllerThreads, stop); err != nil {
2✔
637
                                log.Log.Warningf("error running the backup controller: %v", err)
1✔
638
                        }
1✔
639
                }()
640

641
                cache.WaitForCacheSync(stop, vca.persistentVolumeClaimInformer.HasSynced, vca.namespaceInformer.HasSynced, vca.resourceQuotaInformer.HasSynced)
1✔
642
                close(vca.readyChan)
1✔
643
                metrics.SetVirtControllerLeading()
1✔
644
        }
645
}
646

647
func (vca *VirtControllerApp) newRecorder(namespace string, componentName string) record.EventRecorder {
×
648
        eventBroadcaster := record.NewBroadcaster()
×
649
        eventBroadcaster.StartRecordingToSink(&k8coresv1.EventSinkImpl{Interface: vca.clientSet.CoreV1().Events(namespace)})
×
650
        return eventBroadcaster.NewRecorder(scheme.Scheme, k8sv1.EventSource{Component: componentName})
×
651
}
×
652

653
func (vca *VirtControllerApp) initCommon() {
×
654
        var err error
×
655

×
656
        virtClient, err := kubecli.GetKubevirtClient()
×
657
        if err != nil {
×
658
                golog.Fatal(err)
×
659
        }
×
660

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

×
663
        netAnnotationsGenerator := netannotations.NewGenerator(vca.clusterConfig)
×
664
        storageAnnotationsGenerator := storageannotations.NewGenerator(vca.clusterConfig)
×
665

×
666
        vca.templateService = services.NewTemplateService(vca.launcherImage,
×
667
                vca.launcherQemuTimeout,
×
668
                vca.virtShareDir,
×
669
                vca.ephemeralDiskDir,
×
670
                vca.containerDiskDir,
×
671
                vca.hotplugDiskDir,
×
672
                vca.imagePullSecret,
×
673
                vca.persistentVolumeClaimCache,
×
674
                virtClient,
×
675
                vca.clusterConfig,
×
676
                vca.launcherSubGid,
×
677
                vca.exporterImage,
×
678
                vca.resourceQuotaInformer.GetStore(),
×
679
                vca.namespaceStore,
×
680
                services.WithSidecarCreator(
×
681
                        func(vmi *v1.VirtualMachineInstance, _ *v1.KubeVirtConfiguration) (hooks.HookSidecarList, error) {
×
682
                                return hooks.UnmarshalHookSidecarList(vmi)
×
683
                        }),
×
684
                services.WithSidecarCreator(netbinding.NetBindingPluginSidecarList),
685
                services.WithNetMemoryCalculator(netresources.MemoryCalculator{}),
686
                services.WithAnnotationsGenerators(netAnnotationsGenerator, storageannotations.Generator{}),
687
                services.WithNetTargetAnnotationsGenerator(netAnnotationsGenerator),
688
        )
689

690
        topologyHinter := topology.NewTopologyHinter(vca.nodeInformer.GetStore(), vca.vmiInformer.GetStore(), vca.clusterConfig)
×
691

×
692
        vca.vmiController, err = vmi.NewController(vca.templateService,
×
693
                vca.vmiInformer,
×
694
                vca.vmInformer,
×
695
                vca.kvPodInformer,
×
696
                vca.persistentVolumeClaimInformer,
×
697
                vca.migrationInformer,
×
698
                vca.storageClassInformer,
×
699
                vca.vmiRecorder,
×
700
                vca.clientSet,
×
701
                vca.dataVolumeInformer,
×
702
                vca.storageProfileInformer,
×
703
                vca.cdiInformer,
×
704
                vca.cdiConfigInformer,
×
705
                vca.kubeVirtInformer,
×
706
                vca.clusterConfig,
×
707
                topologyHinter,
×
708
                netAnnotationsGenerator,
×
709
                storageAnnotationsGenerator,
×
710
                netcontrollers.UpdateVMIStatus,
×
711
                func(field *k8sfield.Path, vmiSpec *v1.VirtualMachineInstanceSpec, clusterCfg *virtconfig.ClusterConfig) []metav1.StatusCause {
×
712
                        return netadmitter.ValidateCreation(field, vmiSpec, clusterCfg)
×
713
                },
×
714
                netmigration.NewEvaluator(),
715
                vca.additionalLauncherAnnotationsSync,
716
                vca.additionalLauncherLabelsSync,
717
        )
718
        if err != nil {
×
719
                panic(err)
×
720
        }
721

722
        recorder := vca.newRecorder(k8sv1.NamespaceAll, "node-controller")
×
723
        vca.nodeController, err = node.NewController(vca.clientSet, vca.nodeInformer, vca.vmiInformer, recorder)
×
724
        if err != nil {
×
725
                panic(err)
×
726
        }
727
        // Adding a timeout to the clientSet of the migration controller, to avoid potential deadlocks
728
        clientSet, err := vca.clientSet.SetRestTimeout(migrationControllerRestTimeout)
×
729
        if err != nil {
×
730
                panic(err)
×
731
        }
732
        vca.migrationController, err = migration.NewController(
×
733
                vca.templateService,
×
734
                vca.vmiInformer,
×
735
                vca.kvPodInformer,
×
736
                vca.migrationInformer,
×
737
                vca.nodeInformer,
×
738
                vca.persistentVolumeClaimInformer,
×
739
                vca.storageClassInformer,
×
740
                vca.storageProfileInformer,
×
741
                vca.migrationPolicyInformer,
×
742
                vca.resourceQuotaInformer,
×
743
                vca.kubeVirtInformer,
×
744
                vca.vmiRecorder,
×
745
                clientSet,
×
746
                vca.clusterConfig,
×
747
                netAnnotationsGenerator,
×
748
        )
×
749
        if err != nil {
×
750
                panic(err)
×
751
        }
752

753
        vca.nodeTopologyUpdater = topology.NewNodeTopologyUpdater(vca.clientSet, topologyHinter, vca.nodeInformer)
×
754
}
755

756
func (vca *VirtControllerApp) initReplicaSet() {
×
757
        var err error
×
758
        recorder := vca.newRecorder(k8sv1.NamespaceAll, "virtualmachinereplicaset-controller")
×
759
        vca.rsController, err = replicaset.NewController(vca.vmiInformer, vca.rsInformer, recorder, vca.clientSet, controller.BurstReplicas)
×
760
        if err != nil {
×
761
                panic(err)
×
762
        }
763
}
764

765
func (vca *VirtControllerApp) initPool() {
×
766
        var err error
×
767
        recorder := vca.newRecorder(k8sv1.NamespaceAll, "virtualmachinepool-controller")
×
768
        vca.poolController, err = pool.NewController(vca.clientSet,
×
769
                vca.vmiInformer,
×
770
                vca.vmInformer,
×
771
                vca.poolInformer,
×
772
                vca.persistentVolumeClaimInformer,
×
773
                vca.dataVolumeInformer,
×
774
                vca.controllerRevisionInformer,
×
775
                recorder,
×
776
                controller.BurstReplicas)
×
777
        if err != nil {
×
778
                panic(err)
×
779
        }
780
}
781

782
func (vca *VirtControllerApp) initVirtualMachines() {
×
783
        var err error
×
784
        recorder := vca.newRecorder(k8sv1.NamespaceAll, "virtualmachine-controller")
×
785

×
786
        vca.vmController, err = vm.NewController(
×
787
                vca.vmiInformer,
×
788
                vca.vmInformer,
×
789
                vca.dataVolumeInformer,
×
790
                vca.dataSourceInformer,
×
791
                vca.kubeVirtInformer,
×
792
                vca.namespaceInformer,
×
793
                vca.persistentVolumeClaimInformer,
×
794
                vca.controllerRevisionInformer,
×
795
                recorder,
×
796
                vca.clientSet,
×
797
                vca.clusterConfig,
×
798
                netcontrollers.NewVMController(
×
799
                        vca.clientSet.GeneratedKubeVirtClient(),
×
800
                ),
×
801
                vm.NewFirmwareController(vca.clientSet.GeneratedKubeVirtClient()),
×
802
                instancetypecontroller.New(
×
803
                        vca.instancetypeInformer.GetStore(),
×
804
                        vca.clusterInstancetypeInformer.GetStore(),
×
805
                        vca.preferenceInformer.GetStore(),
×
806
                        vca.clusterPreferenceInformer.GetStore(),
×
807
                        vca.controllerRevisionInformer.GetStore(),
×
808
                        vca.clientSet,
×
809
                        vca.clusterConfig,
×
810
                        recorder,
×
811
                ),
×
812
                vca.additionalLauncherAnnotationsSync,
×
813
                vca.additionalLauncherLabelsSync,
×
814
        )
×
815
        if err != nil {
×
816
                panic(err)
×
817
        }
818
}
819

820
func (vca *VirtControllerApp) initDisruptionBudgetController() {
×
821
        var err error
×
822
        recorder := vca.newRecorder(k8sv1.NamespaceAll, "disruptionbudget-controller")
×
823
        vca.disruptionBudgetController, err = disruptionbudget.NewDisruptionBudgetController(
×
824
                vca.vmiInformer,
×
825
                vca.pdbInformer,
×
826
                vca.allPodInformer,
×
827
                vca.migrationInformer,
×
828
                recorder,
×
829
                vca.clientSet,
×
830
        )
×
831
        if err != nil {
×
832
                panic(err)
×
833
        }
834
}
835

836
func (vca *VirtControllerApp) initWorkloadUpdaterController() {
×
837
        var err error
×
838
        recorder := vca.newRecorder(k8sv1.NamespaceAll, "workload-update-controller")
×
839
        vca.workloadUpdateController, err = workloadupdater.NewWorkloadUpdateController(
×
840
                vca.launcherImage,
×
841
                vca.vmiInformer,
×
842
                vca.kvPodInformer,
×
843
                vca.migrationInformer,
×
844
                vca.kubeVirtInformer,
×
845
                recorder,
×
846
                vca.clientSet,
×
847
                vca.clusterConfig)
×
848
        if err != nil {
×
849
                panic(err)
×
850
        }
851
}
852

853
func (vca *VirtControllerApp) initEvacuationController() {
×
854
        var err error
×
855
        recorder := vca.newRecorder(k8sv1.NamespaceAll, "evacuation-controller")
×
856
        vca.evacuationController, err = evacuation.NewEvacuationController(
×
857
                vca.vmiInformer,
×
858
                vca.migrationInformer,
×
859
                vca.nodeInformer,
×
860
                vca.kvPodInformer,
×
861
                recorder,
×
862
                vca.clientSet,
×
863
                vca.clusterConfig,
×
864
        )
×
865
        if err != nil {
×
866
                panic(err)
×
867
        }
868
}
869

870
func (vca *VirtControllerApp) initSnapshotController() {
×
871
        recorder := vca.newRecorder(k8sv1.NamespaceAll, "snapshot-controller")
×
872
        vca.snapshotController = &snapshot.VMSnapshotController{
×
873
                Client:                    vca.clientSet,
×
874
                VMSnapshotInformer:        vca.vmSnapshotInformer,
×
875
                VMSnapshotContentInformer: vca.vmSnapshotContentInformer,
×
876
                VMInformer:                vca.vmInformer,
×
877
                VMIInformer:               vca.vmiInformer,
×
878
                StorageClassInformer:      vca.storageClassInformer,
×
879
                StorageProfileInformer:    vca.storageProfileInformer,
×
880
                PVCInformer:               vca.persistentVolumeClaimInformer,
×
881
                CRDInformer:               vca.crdInformer,
×
882
                PodInformer:               vca.allPodInformer,
×
883
                DVInformer:                vca.dataVolumeInformer,
×
884
                CRInformer:                vca.controllerRevisionInformer,
×
885
                Recorder:                  recorder,
×
886
                ResyncPeriod:              vca.snapshotControllerResyncPeriod,
×
887
        }
×
888
        if err := vca.snapshotController.Init(); err != nil {
×
889
                panic(err)
×
890
        }
891
}
892

893
func (vca *VirtControllerApp) initRestoreController() {
×
894
        recorder := vca.newRecorder(k8sv1.NamespaceAll, "restore-controller")
×
895
        vca.restoreController = &snapshot.VMRestoreController{
×
896
                Client:                    vca.clientSet,
×
897
                VMRestoreInformer:         vca.vmRestoreInformer,
×
898
                VMSnapshotInformer:        vca.vmSnapshotInformer,
×
899
                VMSnapshotContentInformer: vca.vmSnapshotContentInformer,
×
900
                VMInformer:                vca.vmInformer,
×
901
                VMIInformer:               vca.vmiInformer,
×
902
                DataVolumeInformer:        vca.dataVolumeInformer,
×
903
                PVCInformer:               vca.persistentVolumeClaimInformer,
×
904
                StorageClassInformer:      vca.storageClassInformer,
×
905
                VolumeSnapshotProvider:    vca.snapshotController,
×
906
                Recorder:                  recorder,
×
907
                CRInformer:                vca.controllerRevisionInformer,
×
908
        }
×
909
        if err := vca.restoreController.Init(); err != nil {
×
910
                panic(err)
×
911
        }
912
}
913

914
func (vca *VirtControllerApp) initExportController() {
×
915
        recorder := vca.newRecorder(k8sv1.NamespaceAll, "export-controller")
×
916
        vca.exportController = &export.VMExportController{
×
917
                ManifestRenderer:            vca.templateService,
×
918
                Client:                      vca.clientSet,
×
919
                VMExportInformer:            vca.vmExportInformer,
×
920
                PVCInformer:                 vca.persistentVolumeClaimInformer,
×
921
                PodInformer:                 vca.allPodInformer,
×
922
                DataVolumeInformer:          vca.dataVolumeInformer,
×
923
                ServiceInformer:             vca.exportServiceInformer,
×
924
                Recorder:                    recorder,
×
925
                ConfigMapInformer:           vca.caExportConfigMapInformer,
×
926
                IngressCache:                vca.ingressCache,
×
927
                RouteCache:                  vca.routeCache,
×
928
                KubevirtNamespace:           vca.kubevirtNamespace,
×
929
                RouteConfigMapInformer:      vca.exportRouteConfigMapInformer,
×
930
                SecretInformer:              vca.unmanagedSecretInformer,
×
931
                VolumeSnapshotProvider:      vca.snapshotController,
×
932
                VMSnapshotInformer:          vca.vmSnapshotInformer,
×
933
                VMSnapshotContentInformer:   vca.vmSnapshotContentInformer,
×
934
                VMInformer:                  vca.vmInformer,
×
935
                VMIInformer:                 vca.vmiInformer,
×
936
                CRDInformer:                 vca.crdInformer,
×
937
                KubeVirtInformer:            vca.kubeVirtInformer,
×
938
                InstancetypeInformer:        vca.instancetypeInformer,
×
939
                ClusterInstancetypeInformer: vca.clusterInstancetypeInformer,
×
940
                PreferenceInformer:          vca.preferenceInformer,
×
941
                ClusterPreferenceInformer:   vca.clusterPreferenceInformer,
×
942
                ControllerRevisionInformer:  vca.controllerRevisionInformer,
×
943
                VMBackupInformer:            vca.vmBackupInformer,
×
944
                BackupCAConfigMapInformer:   vca.caBackupConfigMapInformer,
×
945
        }
×
946
        if err := vca.exportController.Init(); err != nil {
×
947
                panic(err)
×
948
        }
949
}
950

951
func (vca *VirtControllerApp) initCloneController() {
×
952
        var err error
×
953
        recorder := vca.newRecorder(k8sv1.NamespaceAll, "clone-controller")
×
954
        vca.vmCloneController, err = clonecontroller.NewVmCloneController(
×
955
                vca.clientSet, vca.vmCloneInformer, vca.vmSnapshotInformer, vca.vmRestoreInformer, vca.vmInformer, vca.vmSnapshotContentInformer, vca.persistentVolumeClaimInformer, recorder,
×
956
        )
×
957
        if err != nil {
×
958
                panic(err)
×
959
        }
960
}
961

962
func (vca *VirtControllerApp) initBackupController() {
×
963
        var err error
×
964
        recorder := vca.newRecorder(k8sv1.NamespaceAll, "backup-controller")
×
965
        vca.vmBackupController, err = backup.NewVMBackupController(
×
966
                vca.clientSet,
×
967
                vca.vmBackupInformer,
×
968
                vca.vmBackupTrackerInformer,
×
969
                vca.vmInformer,
×
970
                vca.vmiInformer,
×
971
                vca.persistentVolumeClaimInformer,
×
972
                vca.vmExportInformer,
×
973
                vca.caExportConfigMapInformer,
×
974
                recorder,
×
975
                vca.kubevirtNamespace,
×
976
        )
×
977
        if err != nil {
×
978
                panic(err)
×
979
        }
980
}
981

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

2✔
985
        select {
2✔
986
        case _, opened := <-vca.readyChan:
1✔
987
                if !opened {
2✔
988
                        res["apiserver"] = map[string]interface{}{"leader": "true"}
1✔
989
                        if err := response.WriteHeaderAndJson(http.StatusOK, res, restful.MIME_JSON); err != nil {
1✔
990
                                log.Log.Warningf("failed to return 200 OK reply: %v", err)
×
991
                        }
×
992
                        return
1✔
993
                }
994
        default:
1✔
995
        }
996
        res["apiserver"] = map[string]interface{}{"leader": "false"}
1✔
997
        if err := response.WriteHeaderAndJson(http.StatusOK, res, restful.MIME_JSON); err != nil {
1✔
998
                log.Log.Warningf("failed to return 200 OK reply: %v", err)
×
999
        }
×
1000
}
1001

1002
func (vca *VirtControllerApp) AddFlags() {
×
1003
        vca.InitFlags()
×
1004

×
1005
        leaderelectionconfig.BindFlags(&vca.LeaderElection)
×
1006

×
1007
        vca.BindAddress = defaultHost
×
1008
        vca.Port = defaultPort
×
1009

×
1010
        vca.AddCommonFlags()
×
1011

×
1012
        flag.StringVar(&vca.launcherImage, "launcher-image", launcherImage,
×
1013
                "Shim container for containerized VMIs")
×
1014

×
1015
        flag.StringVar(&vca.exporterImage, "exporter-image", exporterImage,
×
1016
                "Container for exporting VMs and VM images")
×
1017

×
1018
        flag.IntVar(&vca.launcherQemuTimeout, "launcher-qemu-timeout", launcherQemuTimeout,
×
1019
                "Amount of time to wait for qemu")
×
1020

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

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

×
1027
        flag.StringVar(&vca.ephemeralDiskDir, "ephemeral-disk-dir", ephemeralDiskDir,
×
1028
                "Base directory for ephemeral disk data")
×
1029

×
1030
        flag.StringVar(&vca.containerDiskDir, "container-disk-dir", containerDiskDir,
×
1031
                "Base directory for container disk data")
×
1032

×
1033
        flag.StringVar(&vca.hotplugDiskDir, "hotplug-disk-dir", hotplugDiskDir,
×
1034
                "Base directory for hotplug disk data")
×
1035

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

×
1040
        flag.IntVar(&vca.vmiControllerThreads, "vmi-controller-threads", defaultVMIControllerThreads,
×
1041
                "Number of goroutines to run for vmi controller")
×
1042

×
1043
        flag.IntVar(&vca.rsControllerThreads, "rs-controller-threads", defaultControllerThreads,
×
1044
                "Number of goroutines to run for replicaset controller")
×
1045

×
1046
        flag.IntVar(&vca.poolControllerThreads, "pool-controller-threads", defaultControllerThreads,
×
1047
                "Number of goroutines to run for pool controller")
×
1048

×
1049
        flag.IntVar(&vca.vmControllerThreads, "vm-controller-threads", defaultControllerThreads,
×
1050
                "Number of goroutines to run for vm controller")
×
1051

×
1052
        flag.IntVar(&vca.migrationControllerThreads, "migration-controller-threads", defaultControllerThreads,
×
1053
                "Number of goroutines to run for migration controller")
×
1054

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

×
1058
        flag.IntVar(&vca.disruptionBudgetControllerThreads, "disruption-budget-controller-threads", defaultControllerThreads,
×
1059
                "Number of goroutines to run for disruption budget controller")
×
1060

×
1061
        flag.Int64Var(&vca.launcherSubGid, "launcher-subgid", defaultLauncherSubGid,
×
1062
                "ID of subgroup to virt-launcher")
×
1063

×
1064
        flag.IntVar(&vca.snapshotControllerThreads, "snapshot-controller-threads", defaultSnapshotControllerThreads,
×
1065
                "Number of goroutines to run for snapshot controller")
×
1066

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

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

×
1073
        flag.DurationVar(&vca.snapshotControllerResyncPeriod, "snapshot-controller-resync-period", defaultSnapshotControllerResyncPeriod,
×
1074
                "Number of goroutines to run for snapshot controller")
×
1075

×
1076
        flag.DurationVar(&vca.nodeTopologyUpdatePeriod, "node-topology-update-period", defaultNodeTopologyUpdatePeriod,
×
1077
                "Update period for the node topology updater")
×
1078

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

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

×
1085
        flag.IntVar(&vca.cloneControllerThreads, "clone-controller-threads", defaultControllerThreads,
×
1086
                "Number of goroutines to run for clone controller")
×
1087

×
1088
        flag.StringSliceVar(&vca.additionalLauncherAnnotationsSync, "additional-launcher-annotations-sync", []string{},
×
1089
                "Comma separated list of annotation keys which if present on the VM template and so VMI, will be sync to the virt-launcher pod. Supports prefix wildcards via the '*' suffix (for example 'vendor.io/*'). Note, it is unidirectional from VM.spec.template.metadata -> VMI and VMI -> virt-launcher pod")
×
1090

×
1091
        flag.StringSliceVar(&vca.additionalLauncherLabelsSync, "additional-launcher-labels-sync", []string{},
×
1092
                "Comma separated list of labels keys which if present on the VM template and so VMI, will be sync to the virt-launcher pod. Supports prefix wildcards via the '*' suffix (for example 'vendor.io/*'). Note, it is unidirectional from VM.spec.template.metadata -> VMI and VMI -> virt-launcher pod")
×
1093
        flag.IntVar(&vca.backupControllerThreads, "backup-controller-threads", defaultBackupControllerThreads,
×
1094
                "Number of goroutines to run for backup controller")
×
1095
}
×
1096

1097
func (vca *VirtControllerApp) setupLeaderElector() (err error) {
×
1098
        clientConfig, err := kubecli.GetKubevirtClientConfig()
×
1099
        if err != nil {
×
1100
                return
×
1101
        }
×
1102

1103
        clientConfig.RateLimiter =
×
1104
                flowcontrol.NewTokenBucketRateLimiter(
×
1105
                        virtconfig.DefaultVirtControllerQPS,
×
1106
                        virtconfig.DefaultVirtControllerBurst)
×
1107

×
1108
        clientSet, err := kubecli.GetKubevirtClientFromRESTConfig(clientConfig)
×
1109
        if err != nil {
×
1110
                return
×
1111
        }
×
1112

1113
        rl, err := resourcelock.New(vca.LeaderElection.ResourceLock,
×
1114
                vca.kubevirtNamespace,
×
1115
                leaderelectionconfig.DefaultLeaseName,
×
1116
                clientSet.CoreV1(),
×
1117
                clientSet.CoordinationV1(),
×
1118
                resourcelock.ResourceLockConfig{
×
1119
                        Identity:      vca.host,
×
1120
                        EventRecorder: vca.newRecorder(k8sv1.NamespaceAll, leaderelectionconfig.DefaultLeaseName),
×
1121
                })
×
1122

×
1123
        if err != nil {
×
1124
                return
×
1125
        }
×
1126

1127
        vca.leaderElector, err = leaderelection.NewLeaderElector(
×
1128
                leaderelection.LeaderElectionConfig{
×
1129
                        Lock:          rl,
×
1130
                        LeaseDuration: vca.LeaderElection.LeaseDuration.Duration,
×
1131
                        RenewDeadline: vca.LeaderElection.RenewDeadline.Duration,
×
1132
                        RetryPeriod:   vca.LeaderElection.RetryPeriod.Duration,
×
1133
                        Callbacks: leaderelection.LeaderCallbacks{
×
1134
                                OnStartedLeading: vca.onStartedLeading(),
×
1135
                                OnStoppedLeading: func() {
×
1136
                                        golog.Fatal("leaderelection lost")
×
1137
                                },
×
1138
                        },
1139
                })
1140

1141
        return
×
1142
}
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