diff --git a/.github/workflows/dev_test.yaml b/.github/workflows/dev_test.yaml deleted file mode 100644 index 1d6a8390a9..0000000000 --- a/.github/workflows/dev_test.yaml +++ /dev/null @@ -1,89 +0,0 @@ -# Copyright 2024 Flant JSC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -name: Test - -env: - GO_VERSION: "1.22.7" - GINKGO_VERSION: "v2.22.0" - KUBEVIRT_VERSION: "1.3.1" - -on: - workflow_dispatch: - inputs: - pr_number: - required: false - type: number - pull_request: - types: [opened, reopened, synchronize, labeled, unlabeled] - branches: - - main - - chore/ci/add-test-kubevirt - push: - branches: - - main - -defaults: - run: - shell: bash - -concurrency: - group: "${{ github.workflow }}-${{ github.event.number || github.ref }}" - cancel-in-progress: true - -jobs: - kvtest: - runs-on: ubuntu-22.04 - name: Run kubevirt tests - steps: - - name: Set up Go ${{ env.GO_VERSION }} - uses: actions/setup-go@v5 - with: - go-version: "${{ env.GO_VERSION }}" - - - uses: actions/checkout@v4 - with: - ref: ${{ github.event.pull_request.head.sha || github.sha }} - - - name: Prepare environment - run: | - git clone --depth 1 --branch v"${{ env.KUBEVIRT_VERSION }}" https://github.com/kubevirt/kubevirt.git ./kubevirt - cd ./kubevirt - - for p in ../images/virt-artifact/patches/*.patch ; do - echo -n "Apply ${p} ... " - git apply --ignore-space-change --ignore-whitespace ${p} && echo OK || (echo FAIL ; exit 1) - done - - go mod edit -go=${{ env.GO_VERSION }} - go mod download - - go get github.com/opencontainers/runc@v1.1.14 - go get github.com/containers/common@v0.60.4 - - go get github.com/go-openapi/strfmt@v0.23.0 - go get github.com/onsi/gomega/matchers/support/goraph/bipartitegraph@v1.34.1 - go get github.com/cilium/ebpf/btf@v0.11.0 - go get github.com/cilium/ebpf/internal@v0.11.0 - - go get golang.org/x/crypto@v0.31.0 - - go mod vendor - - go install github.com/onsi/ginkgo/v2/ginkgo@${{ env.GINKGO_VERSION }} - - - name: Run unit test virt-controller - run: | - cd ./kubevirt - ginkgo -succinct pkg/virt-controller/... diff --git a/images/virt-artifact/patches/002-fix-virt-monitor-processes-reaping.patch b/images/virt-artifact/patches/002-fix-virt-monitor-processes-reaping.patch deleted file mode 100644 index 0e73542612..0000000000 --- a/images/virt-artifact/patches/002-fix-virt-monitor-processes-reaping.patch +++ /dev/null @@ -1,51 +0,0 @@ -diff --git a/cmd/virt-launcher-monitor/virt-launcher-monitor.go b/cmd/virt-launcher-monitor/virt-launcher-monitor.go -index 323f43edfb..124acbefeb 100644 ---- a/cmd/virt-launcher-monitor/virt-launcher-monitor.go -+++ b/cmd/virt-launcher-monitor/virt-launcher-monitor.go -@@ -189,15 +189,38 @@ func RunAndMonitor(containerDiskDir, uid string) (int, error) { - for sig := range sigs { - switch sig { - case syscall.SIGCHLD: -- var wstatus syscall.WaitStatus -- wpid, err := syscall.Wait4(-1, &wstatus, syscall.WNOHANG, nil) -- if err != nil { -- log.Log.Reason(err).Errorf("Failed to reap process %d", wpid) -+ wpids := make([]int, 0) -+ for { -+ var wstatus syscall.WaitStatus -+ wpid, err := syscall.Wait4(-1, &wstatus, syscall.WNOHANG, nil) -+ -+ if wpid == -1 { -+ if err != nil { -+ if errors.Is(err, syscall.ECHILD) { -+ log.Log.Info("No processes to wait") -+ } else { -+ log.Log.Reason(err).Errorf("Failed to reap process %d", wpid) -+ } -+ } -+ break -+ } -+ -+ if wpid == 0 { -+ log.Log.Info("No processes to reap") -+ break -+ } -+ -+ wpids = append(wpids, wpid) -+ log.Log.Infof("Reaped pid %d with status %d", wpid, int(wstatus)) -+ if wpid == cmd.Process.Pid { -+ log.Log.Infof("Got %s for virt-launcher pid %d, exiting ...", sig.String(), cmd.Process.Pid) -+ exitStatus <- wstatus.ExitStatus() -+ } else { -+ log.Log.Infof("Still wait for virt-launcher pid %d", cmd.Process.Pid) -+ } - } -- -- log.Log.Infof("Reaped pid %d with status %d", wpid, int(wstatus)) -- if wpid == cmd.Process.Pid { -- exitStatus <- wstatus.ExitStatus() -+ if len(wpids) > 0 { -+ log.Log.Infof("Reaped %d processes on %s signal", len(wpids), sig.String()) - } - - default: diff --git a/images/virt-artifact/patches/005-prevent-permanent-patching-of-services.patch b/images/virt-artifact/patches/005-prevent-permanent-patching-of-services.patch deleted file mode 100644 index f99bed4a03..0000000000 --- a/images/virt-artifact/patches/005-prevent-permanent-patching-of-services.patch +++ /dev/null @@ -1,23 +0,0 @@ -diff --git a/pkg/virt-operator/resource/apply/core.go b/pkg/virt-operator/resource/apply/core.go -index 4d507f6153..6cc363548f 100644 ---- a/pkg/virt-operator/resource/apply/core.go -+++ b/pkg/virt-operator/resource/apply/core.go -@@ -437,6 +437,18 @@ func generateServicePatch( - if service.Spec.SessionAffinity == "" { - service.Spec.SessionAffinity = cachedService.Spec.SessionAffinity - } -+ if service.Spec.InternalTrafficPolicy == nil { -+ service.Spec.InternalTrafficPolicy = cachedService.Spec.InternalTrafficPolicy -+ } -+ if service.Spec.ClusterIPs == nil { -+ service.Spec.ClusterIPs = cachedService.Spec.ClusterIPs -+ } -+ if service.Spec.IPFamilies == nil { -+ service.Spec.IPFamilies = cachedService.Spec.IPFamilies -+ } -+ if service.Spec.IPFamilyPolicy == nil { -+ service.Spec.IPFamilyPolicy = cachedService.Spec.IPFamilyPolicy -+ } - - // If the Specs don't equal each other, replace it - if !equality.Semantic.DeepEqual(cachedService.Spec, service.Spec) { diff --git a/images/virt-artifact/patches/007-tolerations-for-strategy-dumper-job.patch b/images/virt-artifact/patches/007-tolerations-for-strategy-dumper-job.patch deleted file mode 100644 index 59669be329..0000000000 --- a/images/virt-artifact/patches/007-tolerations-for-strategy-dumper-job.patch +++ /dev/null @@ -1,24 +0,0 @@ -diff --git a/pkg/virt-operator/strategy_job.go b/pkg/virt-operator/strategy_job.go -index e2838fb7b..a5ab93436 100644 ---- a/pkg/virt-operator/strategy_job.go -+++ b/pkg/virt-operator/strategy_job.go -@@ -61,6 +61,19 @@ func (c *KubeVirtController) generateInstallStrategyJob(infraPlacement *v1.Compo - ServiceAccountName: "kubevirt-operator", - RestartPolicy: k8sv1.RestartPolicyNever, - ImagePullSecrets: config.GetImagePullSecrets(), -+ Tolerations: []k8sv1.Toleration{{Operator: k8sv1.TolerationOpExists}}, -+ Affinity: &k8sv1.Affinity{PodAffinity: &k8sv1.PodAffinity{ -+ RequiredDuringSchedulingIgnoredDuringExecution: []k8sv1.PodAffinityTerm{{ -+ TopologyKey: "kubernetes.io/hostname", -+ LabelSelector: &metav1.LabelSelector{ -+ MatchExpressions: []metav1.LabelSelectorRequirement{{ -+ Key: v1.AppLabel, -+ Operator: metav1.LabelSelectorOpIn, -+ Values: []string{VirtOperator}, -+ }}, -+ }, -+ }}, -+ }}, - - Containers: []k8sv1.Container{ - { diff --git a/images/virt-artifact/patches/011-virt-api-authentication.patch b/images/virt-artifact/patches/011-virt-api-authentication.patch deleted file mode 100644 index d6c9692f96..0000000000 --- a/images/virt-artifact/patches/011-virt-api-authentication.patch +++ /dev/null @@ -1,130 +0,0 @@ -diff --git a/pkg/controller/virtinformers.go b/pkg/controller/virtinformers.go -index 5cbb8197f..82f6f9238 100644 ---- a/pkg/controller/virtinformers.go -+++ b/pkg/controller/virtinformers.go -@@ -300,6 +300,8 @@ type KubeInformerFactory interface { - ResourceQuota() cache.SharedIndexInformer - - K8SInformerFactory() informers.SharedInformerFactory -+ -+ VirtualizationCA() cache.SharedIndexInformer - } - - type kubeInformerFactory struct { -@@ -1293,3 +1295,12 @@ func VolumeSnapshotClassInformer(clientSet kubecli.KubevirtClient, resyncPeriod - lw := cache.NewListWatchFromClient(restClient, "volumesnapshotclasses", k8sv1.NamespaceAll, fields.Everything()) - return cache.NewSharedIndexInformer(lw, &vsv1.VolumeSnapshotClass{}, resyncPeriod, cache.Indexers{}) - } -+ -+func (f *kubeInformerFactory) VirtualizationCA() cache.SharedIndexInformer { -+ return f.getInformer("extensionsVirtualizationCAConfigMapInformer", func() cache.SharedIndexInformer { -+ restClient := f.clientSet.CoreV1().RESTClient() -+ fieldSelector := fields.OneTermEqualSelector("metadata.name", "virtualization-ca") -+ lw := cache.NewListWatchFromClient(restClient, "configmaps", f.kubevirtNamespace, fieldSelector) -+ return cache.NewSharedIndexInformer(lw, &k8sv1.ConfigMap{}, f.defaultResync, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}) -+ }) -+} -diff --git a/pkg/util/tls/tls.go b/pkg/util/tls/tls.go -index e9e140548..e2a349012 100644 ---- a/pkg/util/tls/tls.go -+++ b/pkg/util/tls/tls.go -@@ -132,6 +132,55 @@ func SetupTLSWithCertManager(caManager ClientCAManager, certManager certificate. - return tlsConfig - } - -+func SetupTLSWithVirtualizationCAManager(caManager, virtualizationCAManager ClientCAManager, certManager certificate.Manager, clientAuth tls.ClientAuthType, clusterConfig *virtconfig.ClusterConfig) *tls.Config { -+ tlsConfig := &tls.Config{ -+ GetCertificate: func(info *tls.ClientHelloInfo) (certificate *tls.Certificate, err error) { -+ cert := certManager.Current() -+ if cert == nil { -+ return nil, fmt.Errorf(noSrvCertMessage) -+ } -+ return cert, nil -+ }, -+ GetConfigForClient: func(hi *tls.ClientHelloInfo) (*tls.Config, error) { -+ cert := certManager.Current() -+ if cert == nil { -+ return nil, fmt.Errorf(noSrvCertMessage) -+ } -+ -+ clientCAPool, err := caManager.GetCurrent() -+ if err != nil { -+ log.Log.Reason(err).Error("Failed to get requestheader client CA") -+ return nil, err -+ } -+ -+ virtualizationCA, err := virtualizationCAManager.GetCurrentRaw() -+ if err != nil { -+ log.Log.Reason(err).Error("Failed to get CA from config-map virtualization-ca") -+ return nil, err -+ } -+ -+ clientCAPool.AppendCertsFromPEM(virtualizationCA) -+ -+ kv := clusterConfig.GetConfigFromKubeVirtCR() -+ tlsConfig := getTLSConfiguration(kv) -+ ciphers := CipherSuiteIds(tlsConfig.Ciphers) -+ minTLSVersion := TLSVersion(tlsConfig.MinTLSVersion) -+ config := &tls.Config{ -+ CipherSuites: ciphers, -+ MinVersion: minTLSVersion, -+ Certificates: []tls.Certificate{*cert}, -+ ClientCAs: clientCAPool, -+ ClientAuth: clientAuth, -+ } -+ -+ config.BuildNameToCertificate() -+ return config, nil -+ }, -+ } -+ tlsConfig.BuildNameToCertificate() -+ return tlsConfig -+} -+ - func SetupTLSForVirtHandlerServer(caManager ClientCAManager, certManager certificate.Manager, externallyManaged bool, clusterConfig *virtconfig.ClusterConfig) *tls.Config { - // #nosec cause: InsecureSkipVerify: true - // resolution: Neither the client nor the server should validate anything itself, `VerifyPeerCertificate` is still executed -diff --git a/pkg/virt-api/api.go b/pkg/virt-api/api.go -index 120f2d68f..4b82edd13 100644 ---- a/pkg/virt-api/api.go -+++ b/pkg/virt-api/api.go -@@ -884,7 +884,7 @@ func (app *virtAPIApp) registerMutatingWebhook(informers *webhooks.Informers) { - }) - } - --func (app *virtAPIApp) setupTLS(k8sCAManager kvtls.ClientCAManager, kubevirtCAManager kvtls.ClientCAManager) { -+func (app *virtAPIApp) setupTLS(k8sCAManager, kubevirtCAManager, virtualizationCAManager kvtls.ClientCAManager) { - - // A VerifyClientCertIfGiven request means we're not guaranteed - // a client has been authenticated unless they provide a peer -@@ -901,7 +901,7 @@ func (app *virtAPIApp) setupTLS(k8sCAManager kvtls.ClientCAManager, kubevirtCAMa - // response is given. That status request won't send a peer cert regardless - // if the TLS handshake requests it. As a result, the TLS handshake fails - // and our aggregated endpoint never becomes available. -- app.tlsConfig = kvtls.SetupTLSWithCertManager(k8sCAManager, app.certmanager, tls.VerifyClientCertIfGiven, app.clusterConfig) -+ app.tlsConfig = kvtls.SetupTLSWithVirtualizationCAManager(k8sCAManager, virtualizationCAManager, app.certmanager, tls.VerifyClientCertIfGiven, app.clusterConfig) - app.handlerTLSConfiguration = kvtls.SetupTLSForVirtHandlerClients(kubevirtCAManager, app.handlerCertManager, app.externallyManaged) - } - -@@ -919,10 +919,12 @@ func (app *virtAPIApp) startTLS(informerFactory controller.KubeInformerFactory) - - authConfigMapInformer := informerFactory.ApiAuthConfigMap() - kubevirtCAConfigInformer := informerFactory.KubeVirtCAConfigMap() -+ virtualizationCAConfigInformer := informerFactory.VirtualizationCA() - - k8sCAManager := kvtls.NewKubernetesClientCAManager(authConfigMapInformer.GetStore()) - kubevirtCAInformer := kvtls.NewCAManager(kubevirtCAConfigInformer.GetStore(), app.namespace, app.caConfigMapName) -- app.setupTLS(k8sCAManager, kubevirtCAInformer) -+ virtualizationCAInformer := kvtls.NewCAManager(virtualizationCAConfigInformer.GetStore(), app.namespace, "virtualization-ca") -+ app.setupTLS(k8sCAManager, kubevirtCAInformer, virtualizationCAInformer) - - app.Compose() - -@@ -1007,6 +1009,7 @@ func (app *virtAPIApp) Run() { - - kubeInformerFactory.ApiAuthConfigMap() - kubeInformerFactory.KubeVirtCAConfigMap() -+ kubeInformerFactory.VirtualizationCA() - crdInformer := kubeInformerFactory.CRD() - vmiPresetInformer := kubeInformerFactory.VirtualMachinePreset() - vmRestoreInformer := kubeInformerFactory.VirtualMachineRestore() diff --git a/images/virt-artifact/patches/012-support-kubeconfig-env.patch b/images/virt-artifact/patches/012-support-kubeconfig-env.patch deleted file mode 100644 index 529bd113b6..0000000000 --- a/images/virt-artifact/patches/012-support-kubeconfig-env.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/staging/src/kubevirt.io/client-go/kubecli/kubecli.go b/staging/src/kubevirt.io/client-go/kubecli/kubecli.go -index f5d3982a8..719717247 100644 ---- a/staging/src/kubevirt.io/client-go/kubecli/kubecli.go -+++ b/staging/src/kubevirt.io/client-go/kubecli/kubecli.go -@@ -99,7 +99,7 @@ var once sync.Once - // the different controller generators which normally add these flags too. - func Init() { - if flag.CommandLine.Lookup("kubeconfig") == nil { -- flag.StringVar(&kubeconfig, "kubeconfig", "", "absolute path to the kubeconfig file") -+ flag.StringVar(&kubeconfig, "kubeconfig", os.Getenv("KUBECONFIG"), "absolute path to the kubeconfig file") - } - if flag.CommandLine.Lookup("master") == nil { - flag.StringVar(&master, "master", "", "master url") diff --git a/images/virt-artifact/patches/013-virt-api-rate-limiter.patch b/images/virt-artifact/patches/013-virt-api-rate-limiter.patch deleted file mode 100644 index 39b971c6e0..0000000000 --- a/images/virt-artifact/patches/013-virt-api-rate-limiter.patch +++ /dev/null @@ -1,52 +0,0 @@ -diff --git a/pkg/virt-api/api.go b/pkg/virt-api/api.go -index 120f2d68f..5a92cbaa4 100644 ---- a/pkg/virt-api/api.go -+++ b/pkg/virt-api/api.go -@@ -27,6 +27,7 @@ import ( - "net/http" - "os" - "os/signal" -+ "strconv" - "sync" - "syscall" - "time" -@@ -92,6 +93,9 @@ const ( - httpStatusNotFoundMessage = "Not Found" - httpStatusBadRequestMessage = "Bad Request" - httpStatusInternalServerError = "Internal Server Error" -+ -+ VirtAPIRateLimiterQPSEnvVar = "VIRT_API_RATE_LIMITER_QPS" -+ VirtAPIRateLimiterBurstEnvVar = "VIRT_API_RATE_LIMITER_BURST" - ) - - type VirtApi interface { -@@ -1089,8 +1093,29 @@ func (app *virtAPIApp) shouldChangeLogVerbosity() { - // Update virt-handler rate limiter - func (app *virtAPIApp) shouldChangeRateLimiter() { - config := app.clusterConfig.GetConfig() -+ - qps := config.APIConfiguration.RestClient.RateLimiter.TokenBucketRateLimiter.QPS -+ if os.Getenv(VirtAPIRateLimiterQPSEnvVar) != "" { -+ qpsFromEnv, err := strconv.ParseFloat(os.Getenv(VirtAPIRateLimiterQPSEnvVar), 32) -+ if err != nil { -+ log.Log.Errorf("failed to parse %s: %s, will use default QPS burst %v", VirtAPIRateLimiterQPSEnvVar, err, qps) -+ } else { -+ qps = float32(qpsFromEnv) -+ log.Log.V(2).Infof("use rate limiter QPS %v from %s", qps, VirtAPIRateLimiterQPSEnvVar) -+ } -+ } -+ - burst := config.APIConfiguration.RestClient.RateLimiter.TokenBucketRateLimiter.Burst -+ if os.Getenv(VirtAPIRateLimiterBurstEnvVar) != "" { -+ burstFromEnv, err := strconv.ParseInt(os.Getenv(VirtAPIRateLimiterBurstEnvVar), 10, 32) -+ if err != nil { -+ log.Log.Errorf("failed to parse %s: %s, will use default burst %d", VirtAPIRateLimiterBurstEnvVar, err, burst) -+ } else { -+ burst = int(burstFromEnv) -+ log.Log.V(2).Infof("use rate limiter burst %v from %s", burst, VirtAPIRateLimiterBurstEnvVar) -+ } -+ } -+ - app.reloadableRateLimiter.Set(flowcontrol.NewTokenBucketRateLimiter(qps, burst)) - log.Log.V(2).Infof("setting rate limiter for the API to %v QPS and %v Burst", qps, burst) - qps = config.WebhookConfiguration.RestClient.RateLimiter.TokenBucketRateLimiter.QPS diff --git a/images/virt-artifact/patches/014-delete-apiserver.patch b/images/virt-artifact/patches/014-delete-apiserver.patch deleted file mode 100644 index 59c3505fb7..0000000000 --- a/images/virt-artifact/patches/014-delete-apiserver.patch +++ /dev/null @@ -1,537 +0,0 @@ -diff --git a/pkg/virt-operator/application.go b/pkg/virt-operator/application.go -index 323d0e34b..f4d52e4db 100644 ---- a/pkg/virt-operator/application.go -+++ b/pkg/virt-operator/application.go -@@ -207,7 +207,6 @@ func Execute() { - DaemonSet: app.informerFactory.OperatorDaemonSet(), - ValidationWebhook: app.informerFactory.OperatorValidationWebhook(), - MutatingWebhook: app.informerFactory.OperatorMutatingWebhook(), -- APIService: app.informerFactory.OperatorAPIService(), - InstallStrategyConfigMap: app.informerFactory.OperatorInstallStrategyConfigMaps(), - InstallStrategyJob: app.informerFactory.OperatorInstallStrategyJob(), - InfrastructurePod: app.informerFactory.OperatorPod(), -@@ -229,7 +228,6 @@ func Execute() { - DaemonSetCache: app.informerFactory.OperatorDaemonSet().GetStore(), - ValidationWebhookCache: app.informerFactory.OperatorValidationWebhook().GetStore(), - MutatingWebhookCache: app.informerFactory.OperatorMutatingWebhook().GetStore(), -- APIServiceCache: app.informerFactory.OperatorAPIService().GetStore(), - InstallStrategyConfigMapCache: app.informerFactory.OperatorInstallStrategyConfigMaps().GetStore(), - InstallStrategyJobCache: app.informerFactory.OperatorInstallStrategyJob().GetStore(), - InfrastructurePodCache: app.informerFactory.OperatorPod().GetStore(), -diff --git a/pkg/virt-operator/kubevirt.go b/pkg/virt-operator/kubevirt.go -index 9152959b4..aff0b023a 100644 ---- a/pkg/virt-operator/kubevirt.go -+++ b/pkg/virt-operator/kubevirt.go -@@ -93,7 +93,6 @@ func NewKubeVirtController( - workqueue.NewItemExponentialFailureRateLimiter(5*time.Second, 1000*time.Second), - &workqueue.BucketRateLimiter{Limiter: rate.NewLimiter(rate.Every(5*time.Second), 1)}, - ) -- - c := KubeVirtController{ - clientset: clientset, - aggregatorClient: aggregatorClient, -@@ -114,7 +113,6 @@ func NewKubeVirtController( - DaemonSet: controller.NewUIDTrackingControllerExpectations(controller.NewControllerExpectationsWithName("DaemonSet")), - ValidationWebhook: controller.NewUIDTrackingControllerExpectations(controller.NewControllerExpectationsWithName("ValidationWebhook")), - MutatingWebhook: controller.NewUIDTrackingControllerExpectations(controller.NewControllerExpectationsWithName("MutatingWebhook")), -- APIService: controller.NewUIDTrackingControllerExpectations(controller.NewControllerExpectationsWithName("APIService")), - SCC: controller.NewUIDTrackingControllerExpectations(controller.NewControllerExpectationsWithName("SCC")), - Route: controller.NewUIDTrackingControllerExpectations(controller.NewControllerExpectationsWithName("Route")), - InstallStrategyConfigMap: controller.NewUIDTrackingControllerExpectations(controller.NewControllerExpectationsWithName("InstallStrategyConfigMap")), -@@ -318,21 +316,6 @@ func NewKubeVirtController( - return nil, err - } - -- _, err = c.informers.APIService.AddEventHandler(cache.ResourceEventHandlerFuncs{ -- AddFunc: func(obj interface{}) { -- c.genericAddHandler(obj, c.kubeVirtExpectations.APIService) -- }, -- DeleteFunc: func(obj interface{}) { -- c.genericDeleteHandler(obj, c.kubeVirtExpectations.APIService) -- }, -- UpdateFunc: func(oldObj, newObj interface{}) { -- c.genericUpdateHandler(oldObj, newObj, c.kubeVirtExpectations.APIService) -- }, -- }) -- if err != nil { -- return nil, err -- } -- - _, err = c.informers.SCC.AddEventHandler(cache.ResourceEventHandlerFuncs{ - AddFunc: func(obj interface{}) { - c.sccAddHandler(obj, c.kubeVirtExpectations.SCC) -diff --git a/pkg/virt-operator/kubevirt_test.go b/pkg/virt-operator/kubevirt_test.go -index e42648749..dbd20d23c 100644 ---- a/pkg/virt-operator/kubevirt_test.go -+++ b/pkg/virt-operator/kubevirt_test.go -@@ -211,8 +211,6 @@ func (k *KubeVirtTestData) BeforeTest() { - k.stores.ValidationWebhookCache = k.informers.ValidationWebhook.GetStore() - k.informers.MutatingWebhook, k.mutatingWebhookSource = testutils.NewFakeInformerFor(&admissionregistrationv1.MutatingWebhookConfiguration{}) - k.stores.MutatingWebhookCache = k.informers.MutatingWebhook.GetStore() -- k.informers.APIService, k.apiserviceSource = testutils.NewFakeInformerFor(&apiregv1.APIService{}) -- k.stores.APIServiceCache = k.informers.APIService.GetStore() - - k.informers.SCC, k.sccSource = testutils.NewFakeInformerFor(&secv1.SecurityContextConstraints{}) - k.stores.SCCCache = k.informers.SCC.GetStore() -@@ -506,8 +504,6 @@ func (k *KubeVirtTestData) deleteResource(resource string, key string) { - k.deleteValidationWebhook(key) - case "mutatingwebhookconfigurations": - k.deleteMutatingWebhook(key) -- case "apiservices": -- k.deleteAPIService(key) - case "jobs": - k.deleteInstallStrategyJob(key) - case "configmaps": -@@ -621,14 +617,6 @@ func (k *KubeVirtTestData) deleteMutatingWebhook(key string) { - k.mockQueue.Wait() - } - --func (k *KubeVirtTestData) deleteAPIService(key string) { -- k.mockQueue.ExpectAdds(1) -- if obj, exists, _ := k.informers.APIService.GetStore().GetByKey(key); exists { -- k.apiserviceSource.Delete(obj.(runtime.Object)) -- } -- k.mockQueue.Wait() --} -- - func (k *KubeVirtTestData) deleteInstallStrategyJob(key string) { - k.mockQueue.ExpectAdds(1) - if obj, exists, _ := k.informers.InstallStrategyJob.GetStore().GetByKey(key); exists { -@@ -1312,12 +1300,6 @@ func (k *KubeVirtTestData) addAllWithExclusionMap(config *util.KubeVirtDeploymen - } - all = append(all, mutatingWebhook) - -- apiServices := components.NewVirtAPIAPIServices(config.GetNamespace()) -- for _, apiService := range apiServices { -- apiService.Spec.CABundle = caBundle -- all = append(all, apiService) -- } -- - validatingWebhook = components.NewOpertorValidatingWebhookConfiguration(NAMESPACE) - for i := range validatingWebhook.Webhooks { - validatingWebhook.Webhooks[i].ClientConfig.CABundle = caBundle -@@ -3138,7 +3120,6 @@ func syncCaches(stop chan struct{}, kvInformer cache.SharedIndexInformer, inform - go informers.DaemonSet.Run(stop) - go informers.ValidationWebhook.Run(stop) - go informers.MutatingWebhook.Run(stop) -- go informers.APIService.Run(stop) - go informers.SCC.Run(stop) - go informers.InstallStrategyJob.Run(stop) - go informers.InstallStrategyConfigMap.Run(stop) -@@ -3164,7 +3145,6 @@ func syncCaches(stop chan struct{}, kvInformer cache.SharedIndexInformer, inform - cache.WaitForCacheSync(stop, informers.DaemonSet.HasSynced) - cache.WaitForCacheSync(stop, informers.ValidationWebhook.HasSynced) - cache.WaitForCacheSync(stop, informers.MutatingWebhook.HasSynced) -- cache.WaitForCacheSync(stop, informers.APIService.HasSynced) - cache.WaitForCacheSync(stop, informers.SCC.HasSynced) - cache.WaitForCacheSync(stop, informers.InstallStrategyJob.HasSynced) - cache.WaitForCacheSync(stop, informers.InstallStrategyConfigMap.HasSynced) -diff --git a/pkg/virt-operator/resource/apply/apiservices.go b/pkg/virt-operator/resource/apply/apiservices.go -deleted file mode 100644 -index 6d741321e..000000000 ---- a/pkg/virt-operator/resource/apply/apiservices.go -+++ /dev/null -@@ -1,92 +0,0 @@ --package apply -- --import ( -- "context" -- "encoding/json" -- "fmt" -- -- "github.com/openshift/library-go/pkg/operator/resource/resourcemerge" -- "k8s.io/apimachinery/pkg/api/equality" -- "k8s.io/apimachinery/pkg/api/errors" -- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -- "k8s.io/apimachinery/pkg/types" -- apiregv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1" -- -- "kubevirt.io/client-go/log" --) -- --func (r *Reconciler) createOrUpdateAPIServices(caBundle []byte) error { -- for _, apiService := range r.targetStrategy.APIServices() { -- err := r.createOrUpdateAPIService(apiService.DeepCopy(), caBundle) -- if err != nil { -- return err -- } -- } -- -- return nil --} -- --func (r *Reconciler) createOrUpdateAPIService(apiService *apiregv1.APIService, caBundle []byte) error { -- version, imageRegistry, id := getTargetVersionRegistryID(r.kv) -- injectOperatorMetadata(r.kv, &apiService.ObjectMeta, version, imageRegistry, id, true) -- apiService.Spec.CABundle = caBundle -- -- var cachedAPIService *apiregv1.APIService -- var err error -- obj, exists, _ := r.stores.APIServiceCache.Get(apiService) -- // since these objects was in the past unmanaged, reconcile and pick it up if it exists -- if !exists { -- cachedAPIService, err = r.aggregatorclient.Get(context.Background(), apiService.Name, metav1.GetOptions{}) -- if errors.IsNotFound(err) { -- exists = false -- } else if err != nil { -- return err -- } else { -- exists = true -- } -- } else if exists { -- cachedAPIService = obj.(*apiregv1.APIService) -- } -- -- if !exists { -- r.expectations.APIService.RaiseExpectations(r.kvKey, 1, 0) -- _, err := r.aggregatorclient.Create(context.Background(), apiService, metav1.CreateOptions{}) -- if err != nil { -- r.expectations.APIService.LowerExpectations(r.kvKey, 1, 0) -- return fmt.Errorf("unable to create apiservice %+v: %v", apiService, err) -- } -- -- return nil -- } -- -- modified := resourcemerge.BoolPtr(false) -- resourcemerge.EnsureObjectMeta(modified, &cachedAPIService.ObjectMeta, apiService.ObjectMeta) -- serviceSame := equality.Semantic.DeepEqual(cachedAPIService.Spec.Service, apiService.Spec.Service) -- certsSame := equality.Semantic.DeepEqual(apiService.Spec.CABundle, cachedAPIService.Spec.CABundle) -- prioritySame := cachedAPIService.Spec.VersionPriority == apiService.Spec.VersionPriority && cachedAPIService.Spec.GroupPriorityMinimum == apiService.Spec.GroupPriorityMinimum -- insecureSame := cachedAPIService.Spec.InsecureSkipTLSVerify == apiService.Spec.InsecureSkipTLSVerify -- // there was no change to metadata, the service and priorities were right -- if !*modified && serviceSame && prioritySame && insecureSame && certsSame { -- log.Log.V(4).Infof("apiservice %v is up-to-date", apiService.GetName()) -- -- return nil -- } -- -- spec, err := json.Marshal(apiService.Spec) -- if err != nil { -- return err -- } -- -- ops, err := getPatchWithObjectMetaAndSpec([]string{}, &apiService.ObjectMeta, spec) -- if err != nil { -- return err -- } -- -- _, err = r.aggregatorclient.Patch(context.Background(), apiService.Name, types.JSONPatchType, generatePatchBytes(ops), metav1.PatchOptions{}) -- if err != nil { -- return fmt.Errorf("unable to patch apiservice %+v: %v", apiService, err) -- } -- log.Log.V(4).Infof("apiservice %v updated", apiService.GetName()) -- -- return nil --} -diff --git a/pkg/virt-operator/resource/apply/core.go b/pkg/virt-operator/resource/apply/core.go -index 4d507f615..3315598a3 100644 ---- a/pkg/virt-operator/resource/apply/core.go -+++ b/pkg/virt-operator/resource/apply/core.go -@@ -363,12 +363,6 @@ func (r *Reconciler) createOrUpdateComponentsWithCertificates(queue workqueue.Ra - return err - } - -- // create/update APIServices -- err = r.createOrUpdateAPIServices(caBundle) -- if err != nil { -- return err -- } -- - // create/update Routes - err = r.createOrUpdateRoutes(caBundle) - if err != nil { -diff --git a/pkg/virt-operator/resource/apply/delete.go b/pkg/virt-operator/resource/apply/delete.go -index d2c8b96f5..ecea83a7b 100644 ---- a/pkg/virt-operator/resource/apply/delete.go -+++ b/pkg/virt-operator/resource/apply/delete.go -@@ -36,7 +36,6 @@ import ( - extv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" -- apiregv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1" - - v1 "kubevirt.io/api/core/v1" - "kubevirt.io/client-go/kubecli" -@@ -215,25 +214,6 @@ func DeleteAll(kv *v1.KubeVirt, - } - } - -- // delete apiservices -- objects = stores.APIServiceCache.List() -- for _, obj := range objects { -- if apiservice, ok := obj.(*apiregv1.APIService); ok && apiservice.DeletionTimestamp == nil { -- if key, err := controller.KeyFunc(apiservice); err == nil { -- expectations.APIService.AddExpectedDeletion(kvkey, key) -- err := aggregatorclient.Delete(context.Background(), apiservice.Name, deleteOptions) -- if err != nil { -- expectations.APIService.DeletionObserved(kvkey, key) -- log.Log.Errorf("Failed to delete apiservice %+v: %v", apiservice, err) -- return err -- } -- } -- } else if !ok { -- log.Log.Errorf(castFailedFmt, obj) -- return nil -- } -- } -- - // delete services - objects = stores.ServiceCache.List() - for _, obj := range objects { -diff --git a/pkg/virt-operator/resource/apply/patches.go b/pkg/virt-operator/resource/apply/patches.go -index 2bd0c313d..e9cd7d820 100644 ---- a/pkg/virt-operator/resource/apply/patches.go -+++ b/pkg/virt-operator/resource/apply/patches.go -@@ -140,10 +140,6 @@ func (c *Customizer) Apply(targetStrategy *install.Strategy) error { - if err != nil { - return err - } -- err = c.GenericApplyPatches(targetStrategy.APIServices()) -- if err != nil { -- return err -- } - err = c.GenericApplyPatches(targetStrategy.CertificateSecrets()) - if err != nil { - return err -diff --git a/pkg/virt-operator/resource/apply/reconcile.go b/pkg/virt-operator/resource/apply/reconcile.go -index 61c04595ea..2b31e9f5e8 100644 ---- a/pkg/virt-operator/resource/apply/reconcile.go -+++ b/pkg/virt-operator/resource/apply/reconcile.go -@@ -39,7 +39,6 @@ import ( - "k8s.io/apimachinery/pkg/labels" - "k8s.io/client-go/tools/record" - "k8s.io/client-go/util/workqueue" -- apiregv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1" - - v1 "kubevirt.io/api/core/v1" - "kubevirt.io/client-go/kubecli" -@@ -886,31 +885,6 @@ func (r *Reconciler) deleteObjectsNotInInstallStrategy() error { - } - } - -- // remove unused APIServices -- objects = r.stores.APIServiceCache.List() -- for _, obj := range objects { -- if apiService, ok := obj.(*apiregv1.APIService); ok && apiService.DeletionTimestamp == nil { -- found := false -- for _, targetAPIService := range r.targetStrategy.APIServices() { -- if targetAPIService.Name == apiService.Name { -- found = true -- break -- } -- } -- if !found { -- if key, err := controller.KeyFunc(apiService); err == nil { -- r.expectations.APIService.AddExpectedDeletion(r.kvKey, key) -- err := r.aggregatorclient.Delete(context.Background(), apiService.Name, deleteOptions) -- if err != nil { -- r.expectations.APIService.DeletionObserved(r.kvKey, key) -- log.Log.Errorf("Failed to delete apiService %+v: %v", apiService, err) -- return err -- } -- } -- } -- } -- } -- - // remove unused Secrets - objects = r.stores.SecretCache.List() - for _, obj := range objects { -diff --git a/pkg/virt-operator/resource/generate/components/apiservices.go b/pkg/virt-operator/resource/generate/components/apiservices.go -deleted file mode 100644 -index cde0dbfc1..000000000 ---- a/pkg/virt-operator/resource/generate/components/apiservices.go -+++ /dev/null -@@ -1,44 +0,0 @@ --package components -- --import ( -- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -- apiregv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1" -- -- v1 "kubevirt.io/api/core/v1" --) -- --func NewVirtAPIAPIServices(installNamespace string) []*apiregv1.APIService { -- apiservices := []*apiregv1.APIService{} -- -- for _, version := range v1.SubresourceGroupVersions { -- subresourceAggregatedApiName := version.Version + "." + version.Group -- -- apiservices = append(apiservices, &apiregv1.APIService{ -- TypeMeta: metav1.TypeMeta{ -- APIVersion: "apiregistration.k8s.io/v1", -- Kind: "APIService", -- }, -- ObjectMeta: metav1.ObjectMeta{ -- Name: subresourceAggregatedApiName, -- Labels: map[string]string{ -- v1.AppLabel: "virt-api-aggregator", -- v1.ManagedByLabel: v1.ManagedByLabelOperatorValue, -- }, -- Annotations: map[string]string{ -- certificatesSecretAnnotationKey: VirtApiCertSecretName, -- }, -- }, -- Spec: apiregv1.APIServiceSpec{ -- Service: &apiregv1.ServiceReference{ -- Namespace: installNamespace, -- Name: VirtApiServiceName, -- }, -- Group: version.Group, -- Version: version.Version, -- GroupPriorityMinimum: 1000, -- VersionPriority: 15, -- }, -- }) -- } -- return apiservices --} -diff --git a/pkg/virt-operator/resource/generate/components/apiservices_test.go b/pkg/virt-operator/resource/generate/components/apiservices_test.go -deleted file mode 100644 -index 8cef02889..000000000 ---- a/pkg/virt-operator/resource/generate/components/apiservices_test.go -+++ /dev/null -@@ -1,19 +0,0 @@ --package components -- --import ( -- . "github.com/onsi/ginkgo/v2" -- . "github.com/onsi/gomega" -- -- v1 "kubevirt.io/api/core/v1" --) -- --var _ = Describe("APIServices", func() { -- -- It("should load one APIService with the correct namespace", func() { -- services := NewVirtAPIAPIServices("mynamespace") -- // a subresource aggregated api endpoint should be registered for -- // each vm/vmi api version -- Expect(services).To(HaveLen(len(v1.SubresourceGroupVersions))) -- Expect(services[0].Spec.Service.Namespace).To(Equal("mynamespace")) -- }) --}) -diff --git a/pkg/virt-operator/resource/generate/install/strategy.go b/pkg/virt-operator/resource/generate/install/strategy.go -index f40ae821ef..9768c7d720 100644 ---- a/pkg/virt-operator/resource/generate/install/strategy.go -+++ b/pkg/virt-operator/resource/generate/install/strategy.go -@@ -86,7 +86,6 @@ type StrategyInterface interface { - DaemonSets() []*appsv1.DaemonSet - ValidatingWebhookConfigurations() []*admissionregistrationv1.ValidatingWebhookConfiguration - MutatingWebhookConfigurations() []*admissionregistrationv1.MutatingWebhookConfiguration -- APIServices() []*apiregv1.APIService - CertificateSecrets() []*corev1.Secret - SCCs() []*secv1.SecurityContextConstraints - ServiceMonitors() []*promv1.ServiceMonitor -@@ -116,7 +115,6 @@ type Strategy struct { - daemonSets []*appsv1.DaemonSet - validatingWebhookConfigurations []*admissionregistrationv1.ValidatingWebhookConfiguration - mutatingWebhookConfigurations []*admissionregistrationv1.MutatingWebhookConfiguration -- apiServices []*apiregv1.APIService - certificateSecrets []*corev1.Secret - sccs []*secv1.SecurityContextConstraints - serviceMonitors []*promv1.ServiceMonitor -@@ -210,10 +208,6 @@ func (ins *Strategy) MutatingWebhookConfigurations() []*admissionregistrationv1. - return ins.mutatingWebhookConfigurations - } - --func (ins *Strategy) APIServices() []*apiregv1.APIService { -- return ins.apiServices --} -- - func (ins *Strategy) CertificateSecrets() []*corev1.Secret { - return ins.certificateSecrets - } -@@ -417,9 +411,6 @@ func dumpInstallStrategyToBytes(strategy *Strategy) []byte { - for _, entry := range strategy.validatingAdmissionPolicies { - marshalutil.MarshallObject(entry, writer) - } -- for _, entry := range strategy.apiServices { -- marshalutil.MarshallObject(entry, writer) -- } - for _, entry := range strategy.deployments { - marshalutil.MarshallObject(entry, writer) - } -@@ -590,7 +581,6 @@ func GenerateCurrentInstallStrategy(config *operatorutil.KubeVirtDeploymentConfi - - strategy.daemonSets = append(strategy.daemonSets, handler) - strategy.sccs = append(strategy.sccs, components.GetAllSCC(config.GetNamespace())...) -- strategy.apiServices = components.NewVirtAPIAPIServices(config.GetNamespace()) - strategy.certificateSecrets = components.NewCertSecrets(config.GetNamespace(), operatorNamespace) - strategy.certificateSecrets = append(strategy.certificateSecrets, components.NewCACertSecrets(operatorNamespace)...) - strategy.configMaps = append(strategy.configMaps, components.NewCAConfigMaps(operatorNamespace)...) -@@ -741,12 +731,6 @@ func loadInstallStrategyFromBytes(data string) (*Strategy, error) { - } - validatingAdmissionPolicy.TypeMeta = obj - strategy.validatingAdmissionPolicies = append(strategy.validatingAdmissionPolicies, validatingAdmissionPolicy) -- case "APIService": -- apiService := &apiregv1.APIService{} -- if err := yaml.Unmarshal([]byte(entry), &apiService); err != nil { -- return nil, err -- } -- strategy.apiServices = append(strategy.apiServices, apiService) - case "Secret": - secret := &corev1.Secret{} - if err := yaml.Unmarshal([]byte(entry), &secret); err != nil { -diff --git a/pkg/virt-operator/util/types.go b/pkg/virt-operator/util/types.go -index 96a2a98da..edbfc5fc1 100644 ---- a/pkg/virt-operator/util/types.go -+++ b/pkg/virt-operator/util/types.go -@@ -39,7 +39,6 @@ type Stores struct { - DaemonSetCache cache.Store - ValidationWebhookCache cache.Store - MutatingWebhookCache cache.Store -- APIServiceCache cache.Store - SCCCache cache.Store - RouteCache cache.Store - InstallStrategyConfigMapCache cache.Store -@@ -68,7 +67,6 @@ func (s *Stores) AllEmpty() bool { - IsStoreEmpty(s.DaemonSetCache) && - IsStoreEmpty(s.ValidationWebhookCache) && - IsStoreEmpty(s.MutatingWebhookCache) && -- IsStoreEmpty(s.APIServiceCache) && - IsStoreEmpty(s.PodDisruptionBudgetCache) && - IsSCCStoreEmpty(s.SCCCache) && - IsStoreEmpty(s.RouteCache) && -@@ -114,7 +112,6 @@ type Expectations struct { - DaemonSet *controller.UIDTrackingControllerExpectations - ValidationWebhook *controller.UIDTrackingControllerExpectations - MutatingWebhook *controller.UIDTrackingControllerExpectations -- APIService *controller.UIDTrackingControllerExpectations - SCC *controller.UIDTrackingControllerExpectations - Route *controller.UIDTrackingControllerExpectations - InstallStrategyConfigMap *controller.UIDTrackingControllerExpectations -@@ -138,7 +135,6 @@ type Informers struct { - DaemonSet cache.SharedIndexInformer - ValidationWebhook cache.SharedIndexInformer - MutatingWebhook cache.SharedIndexInformer -- APIService cache.SharedIndexInformer - SCC cache.SharedIndexInformer - Route cache.SharedIndexInformer - InstallStrategyConfigMap cache.SharedIndexInformer -@@ -164,7 +160,6 @@ func (e *Expectations) DeleteExpectations(key string) { - e.DaemonSet.DeleteExpectations(key) - e.ValidationWebhook.DeleteExpectations(key) - e.MutatingWebhook.DeleteExpectations(key) -- e.APIService.DeleteExpectations(key) - e.SCC.DeleteExpectations(key) - e.Route.DeleteExpectations(key) - e.InstallStrategyConfigMap.DeleteExpectations(key) -@@ -188,7 +183,6 @@ func (e *Expectations) ResetExpectations(key string) { - e.DaemonSet.SetExpectations(key, 0, 0) - e.ValidationWebhook.SetExpectations(key, 0, 0) - e.MutatingWebhook.SetExpectations(key, 0, 0) -- e.APIService.SetExpectations(key, 0, 0) - e.SCC.SetExpectations(key, 0, 0) - e.Route.SetExpectations(key, 0, 0) - e.InstallStrategyConfigMap.SetExpectations(key, 0, 0) -@@ -212,7 +206,6 @@ func (e *Expectations) SatisfiedExpectations(key string) bool { - e.DaemonSet.SatisfiedExpectations(key) && - e.ValidationWebhook.SatisfiedExpectations(key) && - e.MutatingWebhook.SatisfiedExpectations(key) && -- e.APIService.SatisfiedExpectations(key) && - e.SCC.SatisfiedExpectations(key) && - e.Route.SatisfiedExpectations(key) && - e.InstallStrategyConfigMap.SatisfiedExpectations(key) && diff --git a/images/virt-artifact/patches/015-rename-core-resources.patch b/images/virt-artifact/patches/015-rename-core-resources.patch deleted file mode 100644 index c36bd8681f..0000000000 --- a/images/virt-artifact/patches/015-rename-core-resources.patch +++ /dev/null @@ -1,160 +0,0 @@ -diff --git a/pkg/virt-controller/watch/drain/disruptionbudget/disruptionbudget.go b/pkg/virt-controller/watch/drain/disruptionbudget/disruptionbudget.go -index d510bbb57c..914f9a1034 100644 ---- a/pkg/virt-controller/watch/drain/disruptionbudget/disruptionbudget.go -+++ b/pkg/virt-controller/watch/drain/disruptionbudget/disruptionbudget.go -@@ -490,7 +490,10 @@ func (c *DisruptionBudgetController) createPDB(key string, vmi *virtv1.VirtualMa - OwnerReferences: []v1.OwnerReference{ - *v1.NewControllerRef(vmi, virtv1.VirtualMachineInstanceGroupVersionKind), - }, -- GenerateName: "kubevirt-disruption-budget-", -+ GenerateName: "kubevirt-internal-virtualization-disruption-budget-", -+ Labels: map[string]string{ -+ virtv1.VirtualMachineNameLabel: vmi.GetName(), -+ }, - }, - Spec: policyv1.PodDisruptionBudgetSpec{ - MinAvailable: &minAvailable, -diff --git a/pkg/virt-operator/resource/generate/components/serviceaccountnames.go b/pkg/virt-operator/resource/generate/components/serviceaccountnames.go -index 0948629bb5..9aca3b3bd2 100644 ---- a/pkg/virt-operator/resource/generate/components/serviceaccountnames.go -+++ b/pkg/virt-operator/resource/generate/components/serviceaccountnames.go -@@ -1,9 +1,9 @@ - package components - - const ( -- ApiServiceAccountName = "kubevirt-apiserver" -- ControllerServiceAccountName = "kubevirt-controller" -- ExportProxyServiceAccountName = "kubevirt-exportproxy" -- HandlerServiceAccountName = "kubevirt-handler" -+ ApiServiceAccountName = "kubevirt-internal-virtualization-apiserver" -+ ControllerServiceAccountName = "kubevirt-internal-virtualization-controller" -+ ExportProxyServiceAccountName = "kubevirt-internal-virtualization-exportproxy" -+ HandlerServiceAccountName = "kubevirt-internal-virtualization-handler" - OperatorServiceAccountName = "kubevirt-operator" - ) -diff --git a/pkg/virt-operator/resource/generate/components/validatingadmissionpolicy.go b/pkg/virt-operator/resource/generate/components/validatingadmissionpolicy.go -index 5fefec2304..a878bf1856 100644 ---- a/pkg/virt-operator/resource/generate/components/validatingadmissionpolicy.go -+++ b/pkg/virt-operator/resource/generate/components/validatingadmissionpolicy.go -@@ -31,9 +31,9 @@ import ( - ) - - const ( -- validatingAdmissionPolicyBindingName = "kubevirt-node-restriction-binding" -- validatingAdmissionPolicyName = "kubevirt-node-restriction-policy" -- nodeRestrictionAppLabelValue = "kubevirt-node-restriction" -+ validatingAdmissionPolicyBindingName = "kubevirt-internal-virtualization-node-restriction-binding" -+ validatingAdmissionPolicyName = "kubevirt-internal-virtualization-node-restriction-policy" -+ nodeRestrictionAppLabelValue = "kubevirt-internal-virtualization-node-restriction" - - NodeRestrictionErrModifySpec = "this user cannot modify spec of node" - NodeRestrictionErrChangeMetadataFields = "this user can only change allowed metadata fields" -diff --git a/pkg/virt-operator/resource/generate/components/webhooks.go b/pkg/virt-operator/resource/generate/components/webhooks.go -index 1f12d586fc..36cd1e17a3 100644 ---- a/pkg/virt-operator/resource/generate/components/webhooks.go -+++ b/pkg/virt-operator/resource/generate/components/webhooks.go -@@ -859,15 +859,15 @@ const VirtHandlerServiceName = "virt-handler" - - const VirtExportProxyServiceName = "virt-exportproxy" - --const VirtAPIValidatingWebhookName = "virt-api-validator" -+const VirtAPIValidatingWebhookName = "virt-internal-virtualization-api-validator" - - const VirtOperatorServiceName = "kubevirt-operator-webhook" - --const VirtAPIMutatingWebhookName = "virt-api-mutator" -+const VirtAPIMutatingWebhookName = "virt-internal-virtualization-api-mutator" - - const KubevirtOperatorWebhookServiceName = "kubevirt-operator-webhook" - --const KubeVirtOperatorValidatingWebhookName = "virt-operator-validator" -+const KubeVirtOperatorValidatingWebhookName = "virt-internal-virtualization-operator-validator" - - const VMSnapshotValidatePath = "/virtualmachinesnapshots-validate" - -diff --git a/pkg/virt-operator/resource/generate/rbac/apiserver.go b/pkg/virt-operator/resource/generate/rbac/apiserver.go -index 99e8fe12dd..1707ba19da 100644 ---- a/pkg/virt-operator/resource/generate/rbac/apiserver.go -+++ b/pkg/virt-operator/resource/generate/rbac/apiserver.go -@@ -307,7 +307,7 @@ func newApiServerAuthDelegatorClusterRoleBinding(namespace string) *rbacv1.Clust - Kind: "ClusterRoleBinding", - }, - ObjectMeta: metav1.ObjectMeta{ -- Name: "kubevirt-apiserver-auth-delegator", -+ Name: "kubevirt-internal-virtualization-apiserver-auth-delegator", - Labels: map[string]string{ - virtv1.AppLabel: "", - }, -diff --git a/pkg/virt-operator/resource/generate/rbac/cluster.go b/pkg/virt-operator/resource/generate/rbac/cluster.go -index a3c5addcd8..e4eadb48f3 100644 ---- a/pkg/virt-operator/resource/generate/rbac/cluster.go -+++ b/pkg/virt-operator/resource/generate/rbac/cluster.go -@@ -36,8 +36,8 @@ import ( - ) - - const ( -- defaultClusterRoleName = "kubevirt.io:default" -- instancetypeViewClusterRoleName = "instancetype.kubevirt.io:view" -+ defaultClusterRoleName = "kubevirt.internal.virtualization.deckhouse.io:default" -+ instancetypeViewClusterRoleName = "instancetype.kubevirt.internal.virtualization.deckhouse.io:view" - - apiVersion = "version" - apiGuestFs = "guestfs" -@@ -178,7 +178,7 @@ func newAdminClusterRole() *rbacv1.ClusterRole { - Kind: "ClusterRole", - }, - ObjectMeta: metav1.ObjectMeta{ -- Name: "kubevirt.io:admin", -+ Name: "kubevirt.internal.virtualization.deckhouse.io:admin", - Labels: map[string]string{ - virtv1.AppLabel: "", - "rbac.authorization.k8s.io/aggregate-to-admin": "true", -@@ -360,7 +360,7 @@ func newEditClusterRole() *rbacv1.ClusterRole { - Kind: "ClusterRole", - }, - ObjectMeta: metav1.ObjectMeta{ -- Name: "kubevirt.io:edit", -+ Name: "kubevirt.internal.virtualization.deckhouse.io:edit", - Labels: map[string]string{ - virtv1.AppLabel: "", - "rbac.authorization.k8s.io/aggregate-to-edit": "true", -@@ -553,7 +553,7 @@ func newViewClusterRole() *rbacv1.ClusterRole { - Kind: "ClusterRole", - }, - ObjectMeta: metav1.ObjectMeta{ -- Name: "kubevirt.io:view", -+ Name: "kubevirt.internal.virtualization.deckhouse.io:view", - Labels: map[string]string{ - virtv1.AppLabel: "", - "rbac.authorization.k8s.io/aggregate-to-view": "true", -diff --git a/pkg/virt-operator/resource/generate/rbac/exportproxy.go b/pkg/virt-operator/resource/generate/rbac/exportproxy.go -index 071ed91f90..ebc9f2adbd 100644 ---- a/pkg/virt-operator/resource/generate/rbac/exportproxy.go -+++ b/pkg/virt-operator/resource/generate/rbac/exportproxy.go -@@ -23,11 +23,12 @@ import ( - rbacv1 "k8s.io/api/rbac/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" -+ "kubevirt.io/kubevirt/pkg/virt-operator/resource/generate/components" - - virtv1 "kubevirt.io/api/core/v1" - ) - --const ExportProxyServiceAccountName = "kubevirt-exportproxy" -+const ExportProxyServiceAccountName = components.ExportProxyServiceAccountName - - func GetAllExportProxy(namespace string) []runtime.Object { - return []runtime.Object{ -diff --git a/pkg/virt-operator/resource/generate/rbac/operator.go b/pkg/virt-operator/resource/generate/rbac/operator.go -index 160083ac5b..c10a42d6f8 100644 ---- a/pkg/virt-operator/resource/generate/rbac/operator.go -+++ b/pkg/virt-operator/resource/generate/rbac/operator.go -@@ -428,7 +428,7 @@ func newOperatorRoleBinding(namespace string) *rbacv1.RoleBinding { - Kind: "RoleBinding", - }, - ObjectMeta: metav1.ObjectMeta{ -- Name: "kubevirt-operator-rolebinding", -+ Name: components.OperatorServiceAccountName, - Namespace: namespace, - Labels: map[string]string{ - virtv1.AppLabel: "", diff --git a/images/virt-artifact/patches/016-rename-install-strategy-labels.patch b/images/virt-artifact/patches/016-rename-install-strategy-labels.patch deleted file mode 100644 index 977ad2d422..0000000000 --- a/images/virt-artifact/patches/016-rename-install-strategy-labels.patch +++ /dev/null @@ -1,44 +0,0 @@ -diff --git a/pkg/virt-operator/resource/generate/install/strategy.go b/pkg/virt-operator/resource/generate/install/strategy.go -index 2f7c0c51b..f88108fdd 100644 ---- a/pkg/virt-operator/resource/generate/install/strategy.go -+++ b/pkg/virt-operator/resource/generate/install/strategy.go -@@ -253,7 +253,7 @@ func NewInstallStrategyConfigMap(config *operatorutil.KubeVirtDeploymentConfig, - GenerateName: "kubevirt-install-strategy-", - Namespace: config.GetNamespace(), - Labels: map[string]string{ -- v1.ManagedByLabel: v1.ManagedByLabelOperatorValue, -+ v1.ManagedByLabel: "virt-operator-internal-virtualization", - v1.InstallStrategyLabel: "", - }, - Annotations: map[string]string{ -diff --git a/staging/src/kubevirt.io/api/core/v1/types.go b/staging/src/kubevirt.io/api/core/v1/types.go -index cf7648a1f..e633c3919 100644 ---- a/staging/src/kubevirt.io/api/core/v1/types.go -+++ b/staging/src/kubevirt.io/api/core/v1/types.go -@@ -828,13 +828,13 @@ const ( - ManagedByLabelOperatorValue = "virt-operator" - ManagedByLabelOperatorOldValue = "kubevirt-operator" - // This annotation represents the kubevirt version for an install strategy configmap. -- InstallStrategyVersionAnnotation = "kubevirt.io/install-strategy-version" -+ InstallStrategyVersionAnnotation = "install.internal.virtualization.deckhouse.io/install-strategy-version" - // This annotation represents the kubevirt registry used for an install strategy configmap. -- InstallStrategyRegistryAnnotation = "kubevirt.io/install-strategy-registry" -+ InstallStrategyRegistryAnnotation = "install.internal.virtualization.deckhouse.io/install-strategy-registry" - // This annotation represents the kubevirt deployment identifier used for an install strategy configmap. -- InstallStrategyIdentifierAnnotation = "kubevirt.io/install-strategy-identifier" -+ InstallStrategyIdentifierAnnotation = "install.internal.virtualization.deckhouse.io/install-strategy-identifier" - // This annotation shows the enconding used for the manifests in the Install Strategy ConfigMap. -- InstallStrategyConfigMapEncoding = "kubevirt.io/install-strategy-cm-encoding" -+ InstallStrategyConfigMapEncoding = "install.internal.virtualization.deckhouse.io/install-strategy-cm-encoding" - // This annotation is a hash of all customizations that live under spec.CustomizeComponents - KubeVirtCustomizeComponentAnnotationHash = "kubevirt.io/customizer-identifier" - // This annotation represents the kubevirt generation that was used to create a resource -@@ -845,7 +845,7 @@ const ( - EphemeralProvisioningObject string = "kubevirt.io/ephemeral-provisioning" - - // This label indicates the object is a part of the install strategy retrieval process. -- InstallStrategyLabel = "kubevirt.io/install-strategy" -+ InstallStrategyLabel = "install.internal.virtualization.deckhouse.io/install-strategy" - - // Set by virt-operator to coordinate component deletion - VirtOperatorComponentFinalizer string = "kubevirt.io/virtOperatorFinalizer" diff --git a/images/virt-artifact/patches/017-fix-vmi-subresource-url.patch b/images/virt-artifact/patches/017-fix-vmi-subresource-url.patch deleted file mode 100644 index f1ecc8853e..0000000000 --- a/images/virt-artifact/patches/017-fix-vmi-subresource-url.patch +++ /dev/null @@ -1,63 +0,0 @@ -diff --git a/pkg/virt-operator/resource/generate/rbac/controller.go b/pkg/virt-operator/resource/generate/rbac/controller.go -index 0acce8541a..2119b211ee 100644 ---- a/pkg/virt-operator/resource/generate/rbac/controller.go -+++ b/pkg/virt-operator/resource/generate/rbac/controller.go -@@ -363,6 +363,18 @@ func newControllerClusterRole() *rbacv1.ClusterRole { - "*", - }, - }, -+ { -+ APIGroups: []string{ -+ "subresources.virtualization.deckhouse.io", -+ }, -+ Resources: []string{ -+ "virtualmachines/addvolume", -+ "virtualmachines/removevolume", -+ }, -+ Verbs: []string{ -+ "update", -+ }, -+ }, - { - APIGroups: []string{ - "subresources.kubevirt.io", -diff --git a/staging/src/kubevirt.io/client-go/generated/kubevirt/clientset/versioned/typed/core/v1/virtualmachineinstance_expansion.go b/staging/src/kubevirt.io/client-go/generated/kubevirt/clientset/versioned/typed/core/v1/virtualmachineinstance_expansion.go -index 2852d0bdbe..a5384279b3 100644 ---- a/staging/src/kubevirt.io/client-go/generated/kubevirt/clientset/versioned/typed/core/v1/virtualmachineinstance_expansion.go -+++ b/staging/src/kubevirt.io/client-go/generated/kubevirt/clientset/versioned/typed/core/v1/virtualmachineinstance_expansion.go -@@ -31,7 +31,10 @@ import ( - "kubevirt.io/client-go/log" - ) - --const vmiSubresourceURL = "/apis/subresources.kubevirt.io/%s" -+const ( -+ vmiSubresourceURL = "/apis/subresources.kubevirt.io/%s" -+ vmiSubresourceVirtualizationURL = "/apis/subresources.virtualization.deckhouse.io/v1alpha2" // v1alpha2/namespaces/%s/virtualmachines/%s/%s -+) - - type SerialConsoleOptions struct { - ConnectionTimeout time.Duration -@@ -269,9 +272,9 @@ func (c *virtualMachineInstances) AddVolume(ctx context.Context, name string, ad - } - - return c.client.Put(). -- AbsPath(fmt.Sprintf(vmiSubresourceURL, v1.ApiStorageVersion)). -+ AbsPath(vmiSubresourceVirtualizationURL). - Namespace(c.ns). -- Resource("virtualmachineinstances"). -+ Resource("virtualmachines"). - Name(name). - SubResource("addvolume"). - Body(body). -@@ -286,9 +289,9 @@ func (c *virtualMachineInstances) RemoveVolume(ctx context.Context, name string, - } - - return c.client.Put(). -- AbsPath(fmt.Sprintf(vmiSubresourceURL, v1.ApiStorageVersion)). -+ AbsPath(vmiSubresourceVirtualizationURL). - Namespace(c.ns). -- Resource("virtualmachineinstances"). -+ Resource("virtualmachines"). - Name(name). - SubResource("removevolume"). - Body(body). diff --git a/images/virt-artifact/patches/018-rename-devices-kubevirt-io.patch b/images/virt-artifact/patches/018-rename-devices-kubevirt-io.patch deleted file mode 100644 index a4a43bec21..0000000000 --- a/images/virt-artifact/patches/018-rename-devices-kubevirt-io.patch +++ /dev/null @@ -1,49 +0,0 @@ -diff --git a/pkg/virt-controller/services/template.go b/pkg/virt-controller/services/template.go -index d4124ea56..6285dacf6 100644 ---- a/pkg/virt-controller/services/template.go -+++ b/pkg/virt-controller/services/template.go -@@ -66,12 +66,12 @@ const ( - virtExporter = "virt-exporter" - ) - --const KvmDevice = "devices.kubevirt.io/kvm" --const TunDevice = "devices.kubevirt.io/tun" --const VhostNetDevice = "devices.kubevirt.io/vhost-net" --const SevDevice = "devices.kubevirt.io/sev" --const VhostVsockDevice = "devices.kubevirt.io/vhost-vsock" --const PrDevice = "devices.kubevirt.io/pr-helper" -+const KvmDevice = "devices.virtualization.deckhouse.io/kvm" -+const TunDevice = "devices.virtualization.deckhouse.io/tun" -+const VhostNetDevice = "devices.virtualization.deckhouse.io/vhost-net" -+const SevDevice = "devices.virtualization.deckhouse.io/sev" -+const VhostVsockDevice = "devices.virtualization.deckhouse.io/vhost-vsock" -+const PrDevice = "devices.virtualization.deckhouse.io/pr-helper" - - const debugLogs = "debugLogs" - const logVerbosity = "logVerbosity" -diff --git a/pkg/virt-handler/device-manager/common.go b/pkg/virt-handler/device-manager/common.go -index e3f86b117..d7a6d3456 100644 ---- a/pkg/virt-handler/device-manager/common.go -+++ b/pkg/virt-handler/device-manager/common.go -@@ -230,7 +230,7 @@ func gRPCConnect(socketPath string, timeout time.Duration) (*grpc.ClientConn, er - } - - func SocketPath(deviceName string) string { -- return filepath.Join(v1beta1.DevicePluginPath, fmt.Sprintf("kubevirt-%s.sock", deviceName)) -+ return filepath.Join(v1beta1.DevicePluginPath, fmt.Sprintf("virtualization-deckhouse-%s.sock", deviceName)) - } - - func IsChanClosed(ch <-chan struct{}) bool { -diff --git a/pkg/virt-handler/device-manager/generic_device.go b/pkg/virt-handler/device-manager/generic_device.go -index 7baceee6c..3b12f94fd 100644 ---- a/pkg/virt-handler/device-manager/generic_device.go -+++ b/pkg/virt-handler/device-manager/generic_device.go -@@ -41,7 +41,7 @@ import ( - ) - - const ( -- DeviceNamespace = "devices.kubevirt.io" -+ DeviceNamespace = "devices.virtualization.deckhouse.io" - connectionTimeout = 5 * time.Second - ) - diff --git a/images/virt-artifact/patches/019-remove-deprecation-warnings-from-crds.patch b/images/virt-artifact/patches/019-remove-deprecation-warnings-from-crds.patch deleted file mode 100644 index 0052efd931..0000000000 --- a/images/virt-artifact/patches/019-remove-deprecation-warnings-from-crds.patch +++ /dev/null @@ -1,132 +0,0 @@ -diff --git a/pkg/virt-operator/resource/generate/components/crds.go b/pkg/virt-operator/resource/generate/components/crds.go -index e9b4ec2714..e48fed6915 100644 ---- a/pkg/virt-operator/resource/generate/components/crds.go -+++ b/pkg/virt-operator/resource/generate/components/crds.go -@@ -36,8 +36,6 @@ import ( - extv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - k8syaml "k8s.io/apimachinery/pkg/util/yaml" -- "k8s.io/utils/pointer" -- - virtv1 "kubevirt.io/api/core/v1" - exportv1alpha1 "kubevirt.io/api/export/v1alpha1" - exportv1beta1 "kubevirt.io/api/export/v1beta1" -@@ -229,15 +227,15 @@ func NewPresetCrd() (*extv1.CustomResourceDefinition, error) { - Name: "v1", - Served: true, - Storage: false, -- Deprecated: true, -- DeprecationWarning: pointer.String("kubevirt.io/v1 VirtualMachineInstancePresets is now deprecated and will be removed in v2."), -+ Deprecated: false, -+ DeprecationWarning: nil, - }, - { - Name: "v1alpha3", - Served: true, - Storage: true, -- Deprecated: true, -- DeprecationWarning: pointer.String("kubevirt.io/v1alpha3 VirtualMachineInstancePresets is now deprecated and will be removed in v2."), -+ Deprecated: false, -+ DeprecationWarning: nil, - }, - }, - Scope: "Namespaced", -@@ -661,14 +659,14 @@ func NewVirtualMachineInstancetypeCrd() (*extv1.CustomResourceDefinition, error) - Name: instancetypev1alpha1.SchemeGroupVersion.Version, - Served: true, - Storage: false, -- Deprecated: true, -- DeprecationWarning: pointer.String("instancetype.kubevirt.io/v1alpha1 VirtualMachineInstancetypes is now deprecated and will be removed in v1."), -+ Deprecated: false, -+ DeprecationWarning: nil, - }, { - Name: instancetypev1alpha2.SchemeGroupVersion.Version, - Served: true, - Storage: false, -- Deprecated: true, -- DeprecationWarning: pointer.String("instancetype.kubevirt.io/v1alpha2 VirtualMachineInstancetypes is now deprecated and will be removed in v1."), -+ Deprecated: false, -+ DeprecationWarning: nil, - }, { - Name: instancetypev1beta1.SchemeGroupVersion.Version, - Served: true, -@@ -702,14 +700,14 @@ func NewVirtualMachineClusterInstancetypeCrd() (*extv1.CustomResourceDefinition, - Name: instancetypev1alpha1.SchemeGroupVersion.Version, - Served: true, - Storage: false, -- Deprecated: true, -- DeprecationWarning: pointer.String("instancetype.kubevirt.io/v1alpha1 VirtualMachineClusterInstanceTypes is now deprecated and will be removed in v1."), -+ Deprecated: false, -+ DeprecationWarning: nil, - }, { - Name: instancetypev1alpha2.SchemeGroupVersion.Version, - Served: true, - Storage: false, -- Deprecated: true, -- DeprecationWarning: pointer.String("instancetype.kubevirt.io/v1alpha2 VirtualMachineClusterInstanceTypes is now deprecated and will be removed in v1."), -+ Deprecated: false, -+ DeprecationWarning: nil, - }, { - Name: instancetypev1beta1.SchemeGroupVersion.Version, - Served: true, -@@ -744,14 +742,14 @@ func NewVirtualMachinePreferenceCrd() (*extv1.CustomResourceDefinition, error) { - Name: instancetypev1alpha1.SchemeGroupVersion.Version, - Served: true, - Storage: false, -- Deprecated: true, -- DeprecationWarning: pointer.String("instancetype.kubevirt.io/v1alpha1 VirtualMachinePreferences is now deprecated and will be removed in v1."), -+ Deprecated: false, -+ DeprecationWarning: nil, - }, { - Name: instancetypev1alpha2.SchemeGroupVersion.Version, - Served: true, - Storage: false, -- Deprecated: true, -- DeprecationWarning: pointer.String("instancetype.kubevirt.io/v1alpha2 VirtualMachinePreferences is now deprecated and will be removed in v1."), -+ Deprecated: false, -+ DeprecationWarning: nil, - }, { - Name: instancetypev1beta1.SchemeGroupVersion.Version, - Served: true, -@@ -785,14 +783,14 @@ func NewVirtualMachineClusterPreferenceCrd() (*extv1.CustomResourceDefinition, e - Name: instancetypev1alpha1.SchemeGroupVersion.Version, - Served: true, - Storage: false, -- Deprecated: true, -- DeprecationWarning: pointer.String("instancetype.kubevirt.io/v1alpha1 VirtualMachineClusterPreferences is now deprecated and will be removed in v1."), -+ Deprecated: false, -+ DeprecationWarning: nil, - }, { - Name: instancetypev1alpha2.SchemeGroupVersion.Version, - Served: true, - Storage: false, -- Deprecated: true, -- DeprecationWarning: pointer.String("instancetype.kubevirt.io/v1alpha2 VirtualMachineClusterPreferences is now deprecated and will be removed in v1."), -+ Deprecated: false, -+ DeprecationWarning: nil, - }, { - Name: instancetypev1beta1.SchemeGroupVersion.Version, - Served: true, -diff --git a/staging/src/kubevirt.io/api/core/v1/register.go b/staging/src/kubevirt.io/api/core/v1/register.go -index ac213dce04..7096192c7f 100644 ---- a/staging/src/kubevirt.io/api/core/v1/register.go -+++ b/staging/src/kubevirt.io/api/core/v1/register.go -@@ -23,7 +23,6 @@ import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" -- "k8s.io/utils/pointer" - - "kubevirt.io/api/core" - ) -@@ -45,8 +44,8 @@ var ( - Name: "v1alpha3", - Served: true, - Storage: false, -- Deprecated: true, -- DeprecationWarning: pointer.String("kubevirt.io/v1alpha3 is now deprecated and will be removed in a future release."), -+ Deprecated: false, -+ DeprecationWarning: nil, - }, - } - ) diff --git a/images/virt-artifact/patches/020-stop-managing-kvvm-kvvmi-crds.patch b/images/virt-artifact/patches/020-stop-managing-kvvm-kvvmi-crds.patch deleted file mode 100644 index b4ee7acf4b..0000000000 --- a/images/virt-artifact/patches/020-stop-managing-kvvm-kvvmi-crds.patch +++ /dev/null @@ -1,15 +0,0 @@ -diff --git a/pkg/virt-operator/resource/generate/install/strategy.go b/pkg/virt-operator/resource/generate/install/strategy.go -index f88108fdd..071f97705 100644 ---- a/pkg/virt-operator/resource/generate/install/strategy.go -+++ b/pkg/virt-operator/resource/generate/install/strategy.go -@@ -388,8 +388,8 @@ func GenerateCurrentInstallStrategy(config *operatorutil.KubeVirtDeploymentConfi - strategy := &Strategy{} - - functions := []func() (*extv1.CustomResourceDefinition, error){ -- components.NewVirtualMachineInstanceCrd, components.NewPresetCrd, components.NewReplicaSetCrd, -- components.NewVirtualMachineCrd, components.NewVirtualMachineInstanceMigrationCrd, -+ components.NewPresetCrd, components.NewReplicaSetCrd, -+ components.NewVirtualMachineInstanceMigrationCrd, - components.NewVirtualMachineSnapshotCrd, components.NewVirtualMachineSnapshotContentCrd, - components.NewVirtualMachineRestoreCrd, components.NewVirtualMachineInstancetypeCrd, - components.NewVirtualMachineClusterInstancetypeCrd, components.NewVirtualMachinePoolCrd, diff --git a/images/virt-artifact/patches/021-support-qcow2-for-filesystem.patch b/images/virt-artifact/patches/021-support-qcow2-for-filesystem.patch deleted file mode 100644 index ffff7323d0..0000000000 --- a/images/virt-artifact/patches/021-support-qcow2-for-filesystem.patch +++ /dev/null @@ -1,118 +0,0 @@ -diff --git a/pkg/host-disk/host-disk.go b/pkg/host-disk/host-disk.go -index 7ada596d87..5be737e557 100644 ---- a/pkg/host-disk/host-disk.go -+++ b/pkg/host-disk/host-disk.go -@@ -22,6 +22,7 @@ package hostdisk - import ( - "fmt" - "os" -+ "os/exec" - "path" - "path/filepath" - "syscall" -@@ -171,6 +172,15 @@ func createSparseRaw(fullPath string, size int64) (err error) { - return nil - } - -+func createQcow2(fullPath string, size int64) (err error) { -+ log.Log.Infof("Create %s with qcow2 format", fullPath) -+ cmd := exec.Command("qemu-img", "create", "-f", "qcow2", fullPath, fmt.Sprintf("%db", size)) -+ if err = cmd.Run(); err != nil { -+ return fmt.Errorf("failed to create qcow2: %w", err) -+ } -+ return nil -+} -+ - func getPVCDiskImgPath(volumeName string, diskName string) string { - return path.Join(pvcBaseDir, volumeName, diskName) - } -@@ -236,7 +246,7 @@ func (hdc *DiskImgCreator) mountHostDiskAndSetOwnership(vmi *v1.VirtualMachineIn - return err - } - if !fileExists { -- if err := hdc.handleRequestedSizeAndCreateSparseRaw(vmi, diskDir, diskPath, hostDisk); err != nil { -+ if err := hdc.handleRequestedSizeAndCreateQcow2(vmi, diskDir, diskPath, hostDisk); err != nil { - return err - } - } -@@ -248,7 +258,7 @@ func (hdc *DiskImgCreator) mountHostDiskAndSetOwnership(vmi *v1.VirtualMachineIn - return nil - } - --func (hdc *DiskImgCreator) handleRequestedSizeAndCreateSparseRaw(vmi *v1.VirtualMachineInstance, diskDir string, diskPath string, hostDisk *v1.HostDisk) error { -+func (hdc *DiskImgCreator) handleRequestedSizeAndCreateQcow2(vmi *v1.VirtualMachineInstance, diskDir string, diskPath string, hostDisk *v1.HostDisk) error { - size, err := hdc.dirBytesAvailableFunc(diskDir, hdc.minimumPVCReserveBytes) - availableSize := int64(size) - if err != nil { -@@ -261,9 +271,9 @@ func (hdc *DiskImgCreator) handleRequestedSizeAndCreateSparseRaw(vmi *v1.Virtual - return err - } - } -- err = createSparseRaw(diskPath, requestedSize) -+ err = createQcow2(diskPath, requestedSize) - if err != nil { -- log.Log.Reason(err).Errorf("Couldn't create a sparse raw file for disk path: %s, error: %v", diskPath, err) -+ log.Log.Reason(err).Errorf("Couldn't create a qcow2 file for disk path: %s, error: %v", diskPath, err) - return err - } - return nil -diff --git a/pkg/virt-launcher/virtwrap/converter/converter.go b/pkg/virt-launcher/virtwrap/converter/converter.go -index 4a6652872c..3318c1c466 100644 ---- a/pkg/virt-launcher/virtwrap/converter/converter.go -+++ b/pkg/virt-launcher/virtwrap/converter/converter.go -@@ -723,7 +723,7 @@ func Convert_v1_Hotplug_DataVolume_To_api_Disk(name string, disk *api.Disk, c *C - // Convert_v1_FilesystemVolumeSource_To_api_Disk takes a FS source and builds the domain Disk representation - func Convert_v1_FilesystemVolumeSource_To_api_Disk(volumeName string, disk *api.Disk, volumesDiscardIgnore []string) error { - disk.Type = "file" -- disk.Driver.Type = "raw" -+ disk.Driver.Type = "qcow2" - disk.Driver.ErrorPolicy = v1.DiskErrorPolicyStop - disk.Source.File = GetFilesystemVolumePath(volumeName) - if !contains(volumesDiscardIgnore, volumeName) { -@@ -735,7 +735,7 @@ func Convert_v1_FilesystemVolumeSource_To_api_Disk(volumeName string, disk *api. - // Convert_v1_Hotplug_FilesystemVolumeSource_To_api_Disk takes a FS source and builds the KVM Disk representation - func Convert_v1_Hotplug_FilesystemVolumeSource_To_api_Disk(volumeName string, disk *api.Disk, volumesDiscardIgnore []string) error { - disk.Type = "file" -- disk.Driver.Type = "raw" -+ disk.Driver.Type = "qcow2" - disk.Driver.ErrorPolicy = v1.DiskErrorPolicyStop - if !contains(volumesDiscardIgnore, volumeName) { - disk.Driver.Discard = "unmap" -@@ -773,9 +773,37 @@ func Convert_v1_HostDisk_To_api_Disk(volumeName string, path string, disk *api.D - disk.Driver.Type = "raw" - disk.Driver.ErrorPolicy = v1.DiskErrorPolicyStop - disk.Source.File = hostdisk.GetMountedHostDiskPath(volumeName, path) -+ return overrideDiskTypeForFile(disk) -+} -+ -+func overrideDiskTypeForFile(disk *api.Disk) error { -+ diskType, err := getDiskTypeFromPath(disk.Source.File) -+ if err != nil { -+ return err -+ } -+ disk.Driver.Type = diskType - return nil - } - -+func getDiskTypeFromPath(path string) (string, error) { -+ const ( -+ formatQcow2 = "qcow2" -+ formatRaw = "raw" -+ ) -+ info, err := os.Stat(path) -+ if err != nil { -+ if errors.Is(err, os.ErrNotExist) { -+ return formatQcow2, nil -+ } -+ return "", err -+ } -+ mode := info.Mode() -+ if mode&os.ModeDevice != 0 { -+ return formatRaw, nil -+ } -+ return formatQcow2, nil -+} -+ - func Convert_v1_SysprepSource_To_api_Disk(volumeName string, disk *api.Disk) error { - if disk.Type == "lun" { - return fmt.Errorf(deviceTypeNotCompatibleFmt, disk.Alias.GetName()) diff --git a/images/virt-artifact/patches/022-cleanup-error-pods.patch b/images/virt-artifact/patches/022-cleanup-error-pods.patch deleted file mode 100644 index 30e90ccb09..0000000000 --- a/images/virt-artifact/patches/022-cleanup-error-pods.patch +++ /dev/null @@ -1,79 +0,0 @@ -diff --git a/pkg/virt-controller/watch/vmi.go b/pkg/virt-controller/watch/vmi.go -index 19de1a1921..7f101e4710 100644 ---- a/pkg/virt-controller/watch/vmi.go -+++ b/pkg/virt-controller/watch/vmi.go -@@ -19,15 +19,19 @@ - package watch - - import ( -+ "cmp" - "context" - "encoding/json" - "errors" - "fmt" - "maps" -+ "slices" - "sort" - "strings" - "time" - -+ "k8s.io/utils/ptr" -+ - "kubevirt.io/kubevirt/pkg/virt-controller/network" - - "kubevirt.io/kubevirt/pkg/virt-controller/watch/topology" -@@ -1048,6 +1052,9 @@ func (c *VMIController) sync(vmi *virtv1.VirtualMachineInstance, pod *k8sv1.Pod, - log.Log.Reason(err).Errorf("failed to delete orphaned attachment pods %s: %v", controller.VirtualMachineInstanceKey(vmi), err) - // do not return; just log the error - } -+ if err := c.deleteErrorPods(context.Background(), vmi, 3); err != nil { -+ return &syncErrorImpl{fmt.Errorf("failed to delete error pods: %v", err), controller.FailedDeletePodReason} -+ } - - err := c.backendStorage.CreateIfNeededAndUpdateVolumeStatus(vmi) - if err != nil { -@@ -1178,6 +1185,44 @@ func (c *VMIController) sync(vmi *virtv1.VirtualMachineInstance, pod *k8sv1.Pod, - return nil - } - -+func getAge(obj v1.Object) time.Duration { -+ return time.Since(obj.GetCreationTimestamp().Time).Truncate(time.Second) -+} -+ -+func (c *VMIController) deleteErrorPods(ctx context.Context, vmi *virtv1.VirtualMachineInstance, keepCount int) error { -+ pods, err := c.listPodsFromNamespace(vmi.GetNamespace()) -+ if err != nil { -+ return fmt.Errorf("failed to list pods from namespace %s: %v", vmi.GetNamespace(), err) -+ } -+ var errorPods []*k8sv1.Pod -+ for _, pod := range pods { -+ if !controller.IsControlledBy(pod, vmi) { -+ continue -+ } -+ if pod.Status.Phase != k8sv1.PodFailed { -+ continue -+ } -+ if !strings.Contains(pod.GetName(), "virt-launcher") { -+ continue -+ } -+ errorPods = append(errorPods, pod) -+ } -+ if len(errorPods) <= keepCount { -+ return nil -+ } -+ slices.SortFunc(errorPods, func(a, b *k8sv1.Pod) int { -+ return cmp.Compare(getAge(a), getAge(b)) -+ }) -+ -+ for _, pod := range errorPods[keepCount:] { -+ err = c.clientset.CoreV1().Pods(vmi.GetNamespace()).Delete(ctx, pod.GetName(), v1.DeleteOptions{GracePeriodSeconds: ptr.To[int64](0)}) -+ if err != nil { -+ return fmt.Errorf("failed to delete pod %s: %v", pod.GetName(), err) -+ } -+ } -+ return nil -+} -+ - func (c *VMIController) handleSyncDataVolumes(vmi *virtv1.VirtualMachineInstance, dataVolumes []*cdiv1.DataVolume) (bool, bool, syncError) { - - ready := true diff --git a/images/virt-artifact/patches/023-replace-expressions-for-validating-admission-policy.patch b/images/virt-artifact/patches/023-replace-expressions-for-validating-admission-policy.patch deleted file mode 100644 index 23e4c08dca..0000000000 --- a/images/virt-artifact/patches/023-replace-expressions-for-validating-admission-policy.patch +++ /dev/null @@ -1,36 +0,0 @@ -diff --git a/pkg/virt-operator/resource/generate/components/validatingadmissionpolicy.go b/pkg/virt-operator/resource/generate/components/validatingadmissionpolicy.go -index 5fefec2304..20914e8bf6 100644 ---- a/pkg/virt-operator/resource/generate/components/validatingadmissionpolicy.go -+++ b/pkg/virt-operator/resource/generate/components/validatingadmissionpolicy.go -@@ -117,7 +117,7 @@ func NewHandlerV1ValidatingAdmissionPolicy(virtHandlerServiceAccount string) *ad - Variables: []admissionregistrationv1.Variable{ - { - Name: "oldNonKubevirtLabels", -- Expression: `oldObject.metadata.labels.filter(k, !k.contains("kubevirt.io") && k != "cpumanager")`, -+ Expression: `oldObject.metadata.labels.filter(k, !k.contains("kubevirt") && k != "cpumanager" && !k.contains("virtualization.deckhouse.io"))`, - }, - { - Name: "oldLabels", -@@ -125,7 +125,7 @@ func NewHandlerV1ValidatingAdmissionPolicy(virtHandlerServiceAccount string) *ad - }, - { - Name: "newNonKubevirtLabels", -- Expression: `object.metadata.labels.filter(k, !k.contains("kubevirt.io") && k != "cpumanager")`, -+ Expression: `object.metadata.labels.filter(k, !k.contains("kubevirt") && k != "cpumanager" && !k.contains("virtualization.deckhouse.io"))`, - }, - { - Name: "newLabels", -@@ -133,11 +133,11 @@ func NewHandlerV1ValidatingAdmissionPolicy(virtHandlerServiceAccount string) *ad - }, - { - Name: "oldNonKubevirtAnnotations", -- Expression: `oldObject.metadata.annotations.filter(k, !k.contains("kubevirt.io"))`, -+ Expression: `oldObject.metadata.annotations.filter(k, !k.contains("kubevirt") && !k.contains("virtualization.deckhouse.io"))`, - }, - { - Name: "newNonKubevirtAnnotations", -- Expression: `object.metadata.annotations.filter(k, !k.contains("kubevirt.io"))`, -+ Expression: `object.metadata.annotations.filter(k, !k.contains("kubevirt") && !k.contains("virtualization.deckhouse.io"))`, - }, - { - Name: "oldAnnotations", diff --git a/images/virt-artifact/patches/024-cover-kubevirt-metrics.patch b/images/virt-artifact/patches/024-cover-kubevirt-metrics.patch deleted file mode 100644 index 586cd4f502..0000000000 --- a/images/virt-artifact/patches/024-cover-kubevirt-metrics.patch +++ /dev/null @@ -1,279 +0,0 @@ -diff --git a/cmd/virt-handler/virt-handler.go b/cmd/virt-handler/virt-handler.go -index 09b2b53904..aaeafc76f3 100644 ---- a/cmd/virt-handler/virt-handler.go -+++ b/cmd/virt-handler/virt-handler.go -@@ -93,10 +93,12 @@ const ( - defaultWatchdogTimeout = 30 * time.Second - - // Default port that virt-handler listens on. -- defaultPort = 8185 -+ defaultPort = 8185 -+ defaultMetricsPort = 8080 - - // Default address that virt-handler listens on. -- defaultHost = "0.0.0.0" -+ defaultHost = "0.0.0.0" -+ defaultMetricsHost = defaultHost - - hostOverride = "" - -@@ -366,6 +368,8 @@ func (app *virtHandlerApp) Run() { - - promErrCh := make(chan error) - go app.runPrometheusServer(promErrCh) -+ healErrCh := make(chan error) -+ go app.runHealthzServer(healErrCh) - - lifecycleHandler := rest.NewLifecycleHandler( - recorder, -@@ -535,7 +539,6 @@ func (app *virtHandlerApp) runPrometheusServer(errCh chan error) { - mux := restful.NewContainer() - webService := new(restful.WebService) - webService.Path("/").Consumes(restful.MIME_JSON).Produces(restful.MIME_JSON) -- webService.Route(webService.GET("/healthz").To(healthz.KubeConnectionHealthzFuncFactory(app.clusterConfig, apiHealthVersion)).Doc("Health endpoint")) - - componentProfiler := profiler.NewProfileManager(app.clusterConfig) - webService.Route(webService.GET("/start-profiler").To(componentProfiler.HandleStartProfiler).Doc("start profiler endpoint")) -@@ -546,14 +549,23 @@ func (app *virtHandlerApp) runPrometheusServer(errCh chan error) { - log.Log.V(1).Infof("metrics: max concurrent requests=%d", app.MaxRequestsInFlight) - mux.Handle("/metrics", metricshandler.Handler(app.MaxRequestsInFlight)) - server := http.Server{ -- Addr: app.ServiceListen.Address(), -+ Addr: app.ServiceListen.MetricsAddress(), - Handler: mux, -- TLSConfig: app.promTLSConfig, -- // Disable HTTP/2 -- // See CVE-2023-44487 -- TLSNextProto: map[string]func(*http.Server, *tls.Conn, http.Handler){}, - } -- errCh <- server.ListenAndServeTLS("", "") -+ errCh <- server.ListenAndServe() -+} -+ -+func (app *virtHandlerApp) runHealthzServer(errCh chan error) { -+ mux := restful.NewContainer() -+ webService := new(restful.WebService) -+ webService.Path("/").Consumes(restful.MIME_JSON).Produces(restful.MIME_JSON) -+ webService.Route(webService.GET("/healthz").To(healthz.KubeConnectionHealthzFuncFactory(app.clusterConfig, apiHealthVersion)).Doc("Health endpoint")) -+ mux.Add(webService) -+ server := http.Server{ -+ Addr: app.ServiceListen.Address(), -+ Handler: mux, -+ } -+ errCh <- server.ListenAndServe() - } - - func (app *virtHandlerApp) runServer(errCh chan error, consoleHandler *rest.ConsoleHandler, lifecycleHandler *rest.LifecycleHandler) { -@@ -588,7 +600,9 @@ func (app *virtHandlerApp) AddFlags() { - app.InitFlags() - - app.BindAddress = defaultHost -+ app.MetricsBindAddress = defaultMetricsHost - app.Port = defaultPort -+ app.MetricsPort = defaultMetricsPort - - app.AddCommonFlags() - -diff --git a/pkg/service/service.go b/pkg/service/service.go -index 0368a0762b..473328fb4b 100644 ---- a/pkg/service/service.go -+++ b/pkg/service/service.go -@@ -42,6 +42,8 @@ type ServiceListen struct { - Name string - BindAddress string - Port int -+ MetricsBindAddress string -+ MetricsPort int - } - - type ServiceLibvirt struct { -@@ -52,6 +54,10 @@ func (service *ServiceListen) Address() string { - return fmt.Sprintf("%s:%s", service.BindAddress, strconv.Itoa(service.Port)) - } - -+func (service *ServiceListen) MetricsAddress() string { -+ return fmt.Sprintf("%s:%s", service.MetricsBindAddress, strconv.Itoa(service.MetricsPort)) -+} -+ - func (service *ServiceListen) InitFlags() { - flag.CommandLine.AddGoFlag(goflag.CommandLine.Lookup("v")) - flag.CommandLine.AddGoFlag(goflag.CommandLine.Lookup("kubeconfig")) -@@ -61,6 +67,9 @@ func (service *ServiceListen) InitFlags() { - func (service *ServiceListen) AddCommonFlags() { - flag.StringVar(&service.BindAddress, "listen", service.BindAddress, "Address where to listen on") - flag.IntVar(&service.Port, "port", service.Port, "Port to listen on") -+ // default values are taken from the common server counterparts -+ flag.StringVar(&service.MetricsBindAddress, "metrics-listen", service.MetricsBindAddress, "Address for metrics to listen on") -+ flag.IntVar(&service.MetricsPort, "metrics-port", service.MetricsPort, "Port for metrics to listen on") - } - - func (service *ServiceLibvirt) AddLibvirtFlags() { -diff --git a/pkg/virt-api/api.go b/pkg/virt-api/api.go -index a7ea3f44d6..6d9ccd800f 100644 ---- a/pkg/virt-api/api.go -+++ b/pkg/virt-api/api.go -@@ -82,9 +82,11 @@ import ( - const ( - // Default port that virt-api listens on. - defaultPort = 443 -+ defaultMetricsPort = 8080 - - // Default address that virt-api listens on. - defaultHost = "0.0.0.0" -+ defaultMetricsHost = defaultHost - - DefaultConsoleServerPort = 8186 - -@@ -156,6 +158,8 @@ func NewVirtApi() VirtApi { - app := &virtAPIApp{} - app.BindAddress = defaultHost - app.Port = defaultPort -+ app.MetricsBindAddress = defaultMetricsHost -+ app.MetricsPort = defaultMetricsPort - - return app - } -@@ -968,6 +972,19 @@ func (app *virtAPIApp) setupTLS(k8sCAManager, kubevirtCAManager, virtualizationC - app.handlerTLSConfiguration = kvtls.SetupTLSForVirtHandlerClients(kubevirtCAManager, app.handlerCertManager, app.externallyManaged) - } - -+func (app *virtAPIApp) startPrometheusServer(errCh chan error) { -+ mux := restful.NewContainer() -+ webService := new(restful.WebService) -+ webService.Path("/").Consumes(restful.MIME_JSON).Produces(restful.MIME_JSON) -+ mux.Add(webService) -+ mux.Handle("/metrics", promhttp.Handler()) -+ server := http.Server{ -+ Addr: app.ServiceListen.MetricsAddress(), -+ Handler: mux, -+ } -+ errCh <- server.ListenAndServe() -+ -+} - func (app *virtAPIApp) startTLS(informerFactory controller.KubeInformerFactory) error { - - errors := make(chan error) -@@ -991,7 +1008,6 @@ func (app *virtAPIApp) startTLS(informerFactory controller.KubeInformerFactory) - - app.Compose() - -- http.Handle("/metrics", promhttp.Handler()) - server := &http.Server{ - Addr: fmt.Sprintf("%s:%d", app.BindAddress, app.Port), - TLSConfig: app.tlsConfig, -@@ -1127,6 +1143,8 @@ func (app *virtAPIApp) Run() { - go app.certmanager.Start() - go app.handlerCertManager.Start() - -+ promErrCh := make(chan error) -+ go app.startPrometheusServer(promErrCh) - // start TLS server - // tls server will only accept connections when fetching a certificate and internal configuration passed once - err = app.startTLS(kubeInformerFactory) -diff --git a/pkg/virt-controller/watch/application.go b/pkg/virt-controller/watch/application.go -index f80a0653ad..4a8d20d7be 100644 ---- a/pkg/virt-controller/watch/application.go -+++ b/pkg/virt-controller/watch/application.go -@@ -92,8 +92,10 @@ import ( - - const ( - defaultPort = 8182 -+ defaultMetricsPort = 8080 - - defaultHost = "0.0.0.0" -+ defaultMetricsHost = defaultHost - - launcherImage = "virt-launcher" - exporterImage = "virt-exportserver" -@@ -492,10 +494,12 @@ func (vca *VirtControllerApp) Run() { - go promCertManager.Start() - promTLSConfig := kvtls.SetupPromTLS(promCertManager, vca.clusterConfig) - -+ promErrCh := make(chan error) -+ go vca.startPrometheusServer(promErrCh) -+ - go func() { - httpLogger := logger.With("service", "http") - _ = httpLogger.Level(log.INFO).Log("action", "listening", "interface", vca.BindAddress, "port", vca.Port) -- http.Handle("/metrics", promhttp.Handler()) - server := http.Server{ - Addr: vca.Address(), - Handler: http.DefaultServeMux, -@@ -519,6 +523,20 @@ func (vca *VirtControllerApp) Run() { - panic("unreachable") - } - -+func (app *VirtControllerApp) startPrometheusServer(errCh chan error) { -+ mux := restful.NewContainer() -+ webService := new(restful.WebService) -+ webService.Path("/").Consumes(restful.MIME_JSON).Produces(restful.MIME_JSON) -+ mux.Add(webService) -+ mux.Handle("/metrics", promhttp.Handler()) -+ server := http.Server{ -+ Addr: app.ServiceListen.MetricsAddress(), -+ Handler: mux, -+ } -+ errCh <- server.ListenAndServe() -+ -+} -+ - func (vca *VirtControllerApp) onStartedLeading() func(ctx context.Context) { - return func(ctx context.Context) { - stop := ctx.Done() -@@ -896,6 +914,8 @@ func (vca *VirtControllerApp) AddFlags() { - - vca.BindAddress = defaultHost - vca.Port = defaultPort -+ vca.MetricsBindAddress = defaultMetricsHost -+ vca.MetricsPort = defaultMetricsPort - - vca.AddCommonFlags() - -diff --git a/pkg/virt-operator/resource/generate/components/daemonsets.go b/pkg/virt-operator/resource/generate/components/daemonsets.go -index da6e00c783..8fa14e93b5 100644 ---- a/pkg/virt-operator/resource/generate/components/daemonsets.go -+++ b/pkg/virt-operator/resource/generate/components/daemonsets.go -@@ -174,7 +174,7 @@ func NewHandlerDaemonSet(namespace, repository, imagePrefix, version, launcherVe - } - container.Args = []string{ - "--port", -- "8443", -+ "8090", - "--hostname-override", - "$(NODE_NAME)", - "--pod-ip-address", -@@ -192,7 +192,7 @@ func NewHandlerDaemonSet(namespace, repository, imagePrefix, version, launcherVe - { - Name: "metrics", - Protocol: corev1.ProtocolTCP, -- ContainerPort: 8443, -+ ContainerPort: 8080, - }, - } - container.SecurityContext = &corev1.SecurityContext{ -@@ -226,10 +226,10 @@ func NewHandlerDaemonSet(namespace, repository, imagePrefix, version, launcherVe - FailureThreshold: 3, - ProbeHandler: corev1.ProbeHandler{ - HTTPGet: &corev1.HTTPGetAction{ -- Scheme: corev1.URISchemeHTTPS, -+ Scheme: corev1.URISchemeHTTP, - Port: intstr.IntOrString{ - Type: intstr.Int, -- IntVal: 8443, -+ IntVal: 8090, - }, - Path: "/healthz", - }, -@@ -241,10 +241,10 @@ func NewHandlerDaemonSet(namespace, repository, imagePrefix, version, launcherVe - container.ReadinessProbe = &corev1.Probe{ - ProbeHandler: corev1.ProbeHandler{ - HTTPGet: &corev1.HTTPGetAction{ -- Scheme: corev1.URISchemeHTTPS, -+ Scheme: corev1.URISchemeHTTP, - Port: intstr.IntOrString{ - Type: intstr.Int, -- IntVal: 8443, -+ IntVal: 8090, - }, - Path: "/healthz", - }, diff --git a/images/virt-artifact/patches/025-stream-graceful-shutdown.patch b/images/virt-artifact/patches/025-stream-graceful-shutdown.patch deleted file mode 100644 index fcb328b9a3..0000000000 --- a/images/virt-artifact/patches/025-stream-graceful-shutdown.patch +++ /dev/null @@ -1,23 +0,0 @@ -diff --git a/pkg/virt-handler/rest/console.go b/pkg/virt-handler/rest/console.go -index 4eb681018d..f76f6187a7 100644 ---- a/pkg/virt-handler/rest/console.go -+++ b/pkg/virt-handler/rest/console.go -@@ -43,6 +43,8 @@ import ( - - "kubevirt.io/kubevirt/pkg/util" - "kubevirt.io/kubevirt/pkg/virt-handler/isolation" -+ -+ "github.com/gorilla/websocket" - ) - - //const failedRetrieveVMI = "Failed to retrieve VMI" -@@ -326,7 +328,7 @@ func (t *ConsoleHandler) stream(vmi *v1.VirtualMachineInstance, request *restful - - select { - case <-stopCh: -- break -+ clientSocket.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseGoingAway, "close by another connection")) - case err := <-errCh: - if err != nil && err != io.EOF { - log.Log.Object(vmi).Reason(err).Error("Error in proxing websocket and unix socket") - diff --git a/images/virt-artifact/patches/026-add-healthz-to-virt-operator.patch b/images/virt-artifact/patches/026-add-healthz-to-virt-operator.patch deleted file mode 100644 index 649b653958..0000000000 --- a/images/virt-artifact/patches/026-add-healthz-to-virt-operator.patch +++ /dev/null @@ -1,53 +0,0 @@ -diff --git a/pkg/virt-operator/application.go b/pkg/virt-operator/application.go -index 47b4880c38..7e889dd48b 100644 ---- a/pkg/virt-operator/application.go -+++ b/pkg/virt-operator/application.go -@@ -341,8 +341,6 @@ func Execute() { - } - - func (app *VirtOperatorApp) Run() { -- promTLSConfig := kvtls.SetupPromTLS(app.operatorCertManager, app.clusterConfig) -- - go func() { - - mux := http.NewServeMux() -@@ -360,15 +358,34 @@ func (app *VirtOperatorApp) Run() { - restfulContainer.ServeMux = mux - restfulContainer.Add(webService) - -+ server := http.Server{ -+ Addr: app.ServiceListen.MetricsAddress(), -+ Handler: mux, -+ } -+ if err := server.ListenAndServe(); err != nil { -+ golog.Fatal(err) -+ } -+ }() -+ go func() { -+ var handle200 = restful.RouteFunction(func(req *restful.Request, resp *restful.Response) { -+ resp.WriteHeader(http.StatusOK) -+ }) -+ mux := http.NewServeMux() -+ -+ webService := new(restful.WebService) -+ webService.Path("/").Consumes(restful.MIME_JSON).Produces(restful.MIME_JSON) -+ webService.Route(webService.GET("/healthz").To(handle200). -+ Produces(restful.MIME_JSON). -+ Returns(200, "OK", nil)) -+ -+ restfulContainer := restful.NewContainer() -+ restfulContainer.ServeMux = mux -+ restfulContainer.Add(webService) - server := http.Server{ - Addr: app.ServiceListen.Address(), - Handler: mux, -- TLSConfig: promTLSConfig, -- // Disable HTTP/2 -- // See CVE-2023-44487 -- TLSNextProto: map[string]func(*http.Server, *tls.Conn, http.Handler){}, - } -- if err := server.ListenAndServeTLS("", ""); err != nil { -+ if err := server.ListenAndServe(); err != nil { - golog.Fatal(err) - } - }() diff --git a/images/virt-artifact/patches/027-auto-migrate-if-nodeplacement-changed.patch b/images/virt-artifact/patches/027-auto-migrate-if-nodeplacement-changed.patch deleted file mode 100644 index 3773805f3d..0000000000 --- a/images/virt-artifact/patches/027-auto-migrate-if-nodeplacement-changed.patch +++ /dev/null @@ -1,750 +0,0 @@ -diff --git a/pkg/controller/virtinformers.go b/pkg/controller/virtinformers.go -index 72d94b53b5..3a0e46da4a 100644 ---- a/pkg/controller/virtinformers.go -+++ b/pkg/controller/virtinformers.go -@@ -1385,7 +1385,19 @@ func (f *kubeInformerFactory) StorageClass() cache.SharedIndexInformer { - func (f *kubeInformerFactory) Pod() cache.SharedIndexInformer { - return f.getInformer("podInformer", func() cache.SharedIndexInformer { - lw := cache.NewListWatchFromClient(f.clientSet.CoreV1().RESTClient(), "pods", k8sv1.NamespaceAll, fields.Everything()) -- return cache.NewSharedIndexInformer(lw, &k8sv1.Pod{}, f.defaultResync, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}) -+ return cache.NewSharedIndexInformer(lw, &k8sv1.Pod{}, f.defaultResync, cache.Indexers{ -+ cache.NamespaceIndex: cache.MetaNamespaceIndexFunc, -+ "node": func(obj interface{}) ([]string, error) { -+ pod, ok := obj.(*k8sv1.Pod) -+ if !ok { -+ return nil, nil -+ } -+ if pod.Spec.NodeName == "" { -+ return nil, nil -+ } -+ return []string{pod.Spec.NodeName}, nil -+ }, -+ }) - }) - } - -diff --git a/pkg/util/affinity/nodeaffinity.go b/pkg/util/affinity/nodeaffinity.go -new file mode 100644 -index 0000000000..eeadaa6a99 ---- /dev/null -+++ b/pkg/util/affinity/nodeaffinity.go -@@ -0,0 +1,253 @@ -+/* -+Copyright 2020 The Kubernetes Authors. -+ -+Licensed under the Apache License, Version 2.0 (the "License"); -+you may not use this file except in compliance with the License. -+You may obtain a copy of the License at -+ -+ http://www.apache.org/licenses/LICENSE-2.0 -+ -+Unless required by applicable law or agreed to in writing, software -+distributed under the License is distributed on an "AS IS" BASIS, -+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -+See the License for the specific language governing permissions and -+limitations under the License. -+*/ -+ -+package affinity -+ -+import ( -+ v1 "k8s.io/api/core/v1" -+ "k8s.io/apimachinery/pkg/fields" -+ "k8s.io/apimachinery/pkg/labels" -+ "k8s.io/apimachinery/pkg/selection" -+ "k8s.io/apimachinery/pkg/util/errors" -+ "k8s.io/apimachinery/pkg/util/validation/field" -+) -+ -+// LazyErrorNodeSelector is a runtime representation of v1.NodeSelector that -+// only reports parse errors when no terms match. -+type LazyErrorNodeSelector struct { -+ terms []nodeSelectorTerm -+} -+ -+// NewLazyErrorNodeSelector creates a NodeSelector that only reports parse -+// errors when no terms match. -+func NewLazyErrorNodeSelector(ns *v1.NodeSelector, opts ...field.PathOption) *LazyErrorNodeSelector { -+ p := field.ToPath(opts...) -+ parsedTerms := make([]nodeSelectorTerm, 0, len(ns.NodeSelectorTerms)) -+ path := p.Child("nodeSelectorTerms") -+ for i, term := range ns.NodeSelectorTerms { -+ // nil or empty term selects no objects -+ if isEmptyNodeSelectorTerm(&term) { -+ continue -+ } -+ p := path.Index(i) -+ parsedTerms = append(parsedTerms, newNodeSelectorTerm(&term, p)) -+ } -+ return &LazyErrorNodeSelector{ -+ terms: parsedTerms, -+ } -+} -+ -+// Match checks whether the node labels and fields match the selector terms, ORed; -+// nil or empty term matches no objects. -+// Parse errors are only returned if no terms matched. -+func (ns *LazyErrorNodeSelector) Match(node *v1.Node) (bool, error) { -+ if node == nil { -+ return false, nil -+ } -+ nodeLabels := labels.Set(node.Labels) -+ nodeFields := extractNodeFields(node) -+ -+ var errs []error -+ for _, term := range ns.terms { -+ match, tErrs := term.match(nodeLabels, nodeFields) -+ if len(tErrs) > 0 { -+ errs = append(errs, tErrs...) -+ continue -+ } -+ if match { -+ return true, nil -+ } -+ } -+ return false, errors.Flatten(errors.NewAggregate(errs)) -+} -+ -+func isEmptyNodeSelectorTerm(term *v1.NodeSelectorTerm) bool { -+ return len(term.MatchExpressions) == 0 && len(term.MatchFields) == 0 -+} -+ -+func extractNodeFields(n *v1.Node) fields.Set { -+ f := make(fields.Set) -+ if len(n.Name) > 0 { -+ f["metadata.name"] = n.Name -+ } -+ return f -+} -+ -+type nodeSelectorTerm struct { -+ matchLabels labels.Selector -+ matchFields fields.Selector -+ parseErrs []error -+} -+ -+func newNodeSelectorTerm(term *v1.NodeSelectorTerm, path *field.Path) nodeSelectorTerm { -+ var parsedTerm nodeSelectorTerm -+ var errs []error -+ if len(term.MatchExpressions) != 0 { -+ p := path.Child("matchExpressions") -+ parsedTerm.matchLabels, errs = nodeSelectorRequirementsAsSelector(term.MatchExpressions, p) -+ if errs != nil { -+ parsedTerm.parseErrs = append(parsedTerm.parseErrs, errs...) -+ } -+ } -+ if len(term.MatchFields) != 0 { -+ p := path.Child("matchFields") -+ parsedTerm.matchFields, errs = nodeSelectorRequirementsAsFieldSelector(term.MatchFields, p) -+ if errs != nil { -+ parsedTerm.parseErrs = append(parsedTerm.parseErrs, errs...) -+ } -+ } -+ return parsedTerm -+} -+ -+func (t *nodeSelectorTerm) match(nodeLabels labels.Set, nodeFields fields.Set) (bool, []error) { -+ if t.parseErrs != nil { -+ return false, t.parseErrs -+ } -+ if t.matchLabels != nil && !t.matchLabels.Matches(nodeLabels) { -+ return false, nil -+ } -+ if t.matchFields != nil && len(nodeFields) > 0 && !t.matchFields.Matches(nodeFields) { -+ return false, nil -+ } -+ return true, nil -+} -+ -+var validSelectorOperators = []v1.NodeSelectorOperator{ -+ v1.NodeSelectorOpIn, -+ v1.NodeSelectorOpNotIn, -+ v1.NodeSelectorOpExists, -+ v1.NodeSelectorOpDoesNotExist, -+ v1.NodeSelectorOpGt, -+ v1.NodeSelectorOpLt, -+} -+ -+// nodeSelectorRequirementsAsSelector converts the []NodeSelectorRequirement api type into a struct that implements -+// labels.Selector. -+func nodeSelectorRequirementsAsSelector(nsm []v1.NodeSelectorRequirement, path *field.Path) (labels.Selector, []error) { -+ if len(nsm) == 0 { -+ return labels.Nothing(), nil -+ } -+ var errs []error -+ selector := labels.NewSelector() -+ for i, expr := range nsm { -+ p := path.Index(i) -+ var op selection.Operator -+ switch expr.Operator { -+ case v1.NodeSelectorOpIn: -+ op = selection.In -+ case v1.NodeSelectorOpNotIn: -+ op = selection.NotIn -+ case v1.NodeSelectorOpExists: -+ op = selection.Exists -+ case v1.NodeSelectorOpDoesNotExist: -+ op = selection.DoesNotExist -+ case v1.NodeSelectorOpGt: -+ op = selection.GreaterThan -+ case v1.NodeSelectorOpLt: -+ op = selection.LessThan -+ default: -+ errs = append(errs, field.NotSupported(p.Child("operator"), expr.Operator, validSelectorOperators)) -+ continue -+ } -+ r, err := labels.NewRequirement(expr.Key, op, expr.Values, field.WithPath(p)) -+ if err != nil { -+ errs = append(errs, err) -+ } else { -+ selector = selector.Add(*r) -+ } -+ } -+ if len(errs) != 0 { -+ return nil, errs -+ } -+ return selector, nil -+} -+ -+var validFieldSelectorOperators = []v1.NodeSelectorOperator{ -+ v1.NodeSelectorOpIn, -+ v1.NodeSelectorOpNotIn, -+} -+ -+// nodeSelectorRequirementsAsFieldSelector converts the []NodeSelectorRequirement core type into a struct that implements -+// fields.Selector. -+func nodeSelectorRequirementsAsFieldSelector(nsr []v1.NodeSelectorRequirement, path *field.Path) (fields.Selector, []error) { -+ if len(nsr) == 0 { -+ return fields.Nothing(), nil -+ } -+ var errs []error -+ -+ var selectors []fields.Selector -+ for i, expr := range nsr { -+ p := path.Index(i) -+ switch expr.Operator { -+ case v1.NodeSelectorOpIn: -+ if len(expr.Values) != 1 { -+ errs = append(errs, field.Invalid(p.Child("values"), expr.Values, "must have one element")) -+ } else { -+ selectors = append(selectors, fields.OneTermEqualSelector(expr.Key, expr.Values[0])) -+ } -+ -+ case v1.NodeSelectorOpNotIn: -+ if len(expr.Values) != 1 { -+ errs = append(errs, field.Invalid(p.Child("values"), expr.Values, "must have one element")) -+ } else { -+ selectors = append(selectors, fields.OneTermNotEqualSelector(expr.Key, expr.Values[0])) -+ } -+ -+ default: -+ errs = append(errs, field.NotSupported(p.Child("operator"), expr.Operator, validFieldSelectorOperators)) -+ } -+ } -+ -+ if len(errs) != 0 { -+ return nil, errs -+ } -+ return fields.AndSelectors(selectors...), nil -+} -+ -+type RequiredNodeAffinity struct { -+ labelSelector labels.Selector -+ nodeSelector *LazyErrorNodeSelector -+} -+ -+// GetRequiredNodeAffinity returns the parsing result of pod's nodeSelector and nodeAffinity. -+func GetRequiredNodeAffinity(pod *v1.Pod) RequiredNodeAffinity { -+ var selector labels.Selector -+ if len(pod.Spec.NodeSelector) > 0 { -+ selector = labels.SelectorFromSet(pod.Spec.NodeSelector) -+ } -+ // Use LazyErrorNodeSelector for backwards compatibility of parsing errors. -+ var affinity *LazyErrorNodeSelector -+ if pod.Spec.Affinity != nil && -+ pod.Spec.Affinity.NodeAffinity != nil && -+ pod.Spec.Affinity.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution != nil { -+ affinity = NewLazyErrorNodeSelector(pod.Spec.Affinity.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution) -+ } -+ return RequiredNodeAffinity{labelSelector: selector, nodeSelector: affinity} -+} -+ -+// Match checks whether the pod is schedulable onto nodes according to -+// the requirements in both nodeSelector and nodeAffinity. -+func (s RequiredNodeAffinity) Match(node *v1.Node) (bool, error) { -+ if s.labelSelector != nil { -+ if !s.labelSelector.Matches(labels.Set(node.Labels)) { -+ return false, nil -+ } -+ } -+ if s.nodeSelector != nil { -+ return s.nodeSelector.Match(node) -+ } -+ return true, nil -+} -diff --git a/pkg/util/affinity/podaffinity.go b/pkg/util/affinity/podaffinity.go -new file mode 100644 -index 0000000000..b16c2f365f ---- /dev/null -+++ b/pkg/util/affinity/podaffinity.go -@@ -0,0 +1,125 @@ -+/* -+Copyright 2015 The Kubernetes Authors. -+ -+Licensed under the Apache License, Version 2.0 (the "License"); -+you may not use this file except in compliance with the License. -+You may obtain a copy of the License at -+ -+ http://www.apache.org/licenses/LICENSE-2.0 -+ -+Unless required by applicable law or agreed to in writing, software -+distributed under the License is distributed on an "AS IS" BASIS, -+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -+See the License for the specific language governing permissions and -+limitations under the License. -+*/ -+ -+package affinity -+ -+import ( -+ v1 "k8s.io/api/core/v1" -+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -+ "k8s.io/apimachinery/pkg/labels" -+ "k8s.io/apimachinery/pkg/util/sets" -+) -+ -+// AffinityTerm is a processed version of v1.PodAffinityTerm. -+type AffinityTerm struct { -+ Namespaces sets.Set[string] -+ Selector labels.Selector -+ TopologyKey string -+ NamespaceSelector labels.Selector -+} -+ -+// Matches returns true if the pod matches the label selector and namespaces or namespace selector. -+func (at *AffinityTerm) Matches(pod *v1.Pod, nsLabels labels.Set) bool { -+ if at.Namespaces.Has(pod.Namespace) || at.NamespaceSelector.Matches(nsLabels) { -+ return at.Selector.Matches(labels.Set(pod.Labels)) -+ } -+ return false -+} -+ -+func newAffinityTerm(pod *v1.Pod, term *v1.PodAffinityTerm) (*AffinityTerm, error) { -+ selector, err := metav1.LabelSelectorAsSelector(term.LabelSelector) -+ if err != nil { -+ return nil, err -+ } -+ -+ namespaces := getNamespacesFromPodAffinityTerm(pod, term) -+ nsSelector, err := metav1.LabelSelectorAsSelector(term.NamespaceSelector) -+ if err != nil { -+ return nil, err -+ } -+ -+ return &AffinityTerm{Namespaces: namespaces, Selector: selector, TopologyKey: term.TopologyKey, NamespaceSelector: nsSelector}, nil -+} -+ -+// GetAffinityTerms receives a Pod and affinity terms and returns the namespaces and -+// selectors of the terms. -+func GetAffinityTerms(pod *v1.Pod, v1Terms []v1.PodAffinityTerm) ([]AffinityTerm, error) { -+ if v1Terms == nil { -+ return nil, nil -+ } -+ -+ var terms []AffinityTerm -+ for i := range v1Terms { -+ t, err := newAffinityTerm(pod, &v1Terms[i]) -+ if err != nil { -+ // We get here if the label selector failed to process -+ return nil, err -+ } -+ terms = append(terms, *t) -+ } -+ return terms, nil -+} -+ -+// returns a set of names according to the namespaces indicated in podAffinityTerm. -+// If namespaces is empty it considers the given pod's namespace. -+func getNamespacesFromPodAffinityTerm(pod *v1.Pod, podAffinityTerm *v1.PodAffinityTerm) sets.Set[string] { -+ names := sets.Set[string]{} -+ if len(podAffinityTerm.Namespaces) == 0 && podAffinityTerm.NamespaceSelector == nil { -+ names.Insert(pod.Namespace) -+ } else { -+ names.Insert(podAffinityTerm.Namespaces...) -+ } -+ return names -+} -+ -+func GetPodAffinityTerms(affinity *v1.Affinity) (terms []v1.PodAffinityTerm) { -+ if affinity != nil && affinity.PodAffinity != nil { -+ if len(affinity.PodAffinity.RequiredDuringSchedulingIgnoredDuringExecution) != 0 { -+ terms = affinity.PodAffinity.RequiredDuringSchedulingIgnoredDuringExecution -+ } -+ } -+ return terms -+} -+ -+func GetPodAntiAffinityTerms(affinity *v1.Affinity) (terms []v1.PodAffinityTerm) { -+ if affinity != nil && affinity.PodAntiAffinity != nil { -+ if len(affinity.PodAntiAffinity.RequiredDuringSchedulingIgnoredDuringExecution) != 0 { -+ terms = affinity.PodAntiAffinity.RequiredDuringSchedulingIgnoredDuringExecution -+ } -+ } -+ return terms -+} -+ -+func MatchPodAffinityTerms(terms []AffinityTerm, pod *v1.Pod, namespaceLabels labels.Set) bool { -+ if len(terms) == 0 { -+ return true -+ } -+ for _, term := range terms { -+ if term.Matches(pod, namespaceLabels) { -+ return true -+ } -+ } -+ return false -+} -+ -+func MatchPodAntiAffinityTerms(terms []AffinityTerm, pod *v1.Pod, namespaceLabels labels.Set) bool { -+ for _, term := range terms { -+ if term.Matches(pod, namespaceLabels) { -+ return true -+ } -+ } -+ return false -+} -diff --git a/pkg/virt-controller/watch/application.go b/pkg/virt-controller/watch/application.go -index 4a8d20d7be..17711edba5 100644 ---- a/pkg/virt-controller/watch/application.go -+++ b/pkg/virt-controller/watch/application.go -@@ -656,6 +656,9 @@ func (vca *VirtControllerApp) initCommon() { - vca.cdiConfigInformer, - vca.clusterConfig, - topologyHinter, -+ vca.allPodInformer, -+ vca.namespaceInformer, -+ vca.nodeInformer, - ) - if err != nil { - panic(err) -diff --git a/pkg/virt-controller/watch/vmi.go b/pkg/virt-controller/watch/vmi.go -index 0c4bfca389..fa4e86ee17 100644 ---- a/pkg/virt-controller/watch/vmi.go -+++ b/pkg/virt-controller/watch/vmi.go -@@ -69,6 +69,10 @@ import ( - virtconfig "kubevirt.io/kubevirt/pkg/virt-config" - "kubevirt.io/kubevirt/pkg/virt-controller/services" - "kubevirt.io/kubevirt/pkg/virt-controller/watch/descheduler" -+ -+ "k8s.io/apimachinery/pkg/labels" -+ -+ "kubevirt.io/kubevirt/pkg/util/affinity" - ) - - const ( -@@ -92,6 +96,9 @@ func NewVMIController(templateService services.TemplateService, - cdiConfigInformer cache.SharedIndexInformer, - clusterConfig *virtconfig.ClusterConfig, - topologyHinter topology.Hinter, -+ allPodInformer cache.SharedIndexInformer, -+ namespaceInformer cache.SharedIndexInformer, -+ nodeInformer cache.SharedIndexInformer, - ) (*VMIController, error) { - - c := &VMIController{ -@@ -112,12 +119,17 @@ func NewVMIController(templateService services.TemplateService, - topologyHinter: topologyHinter, - cidsMap: newCIDsMap(), - backendStorage: backendstorage.NewBackendStorage(clientset, clusterConfig, storageClassInformer.GetStore(), storageProfileInformer.GetStore(), pvcInformer.GetIndexer()), -+ -+ allPodIndexer: allPodInformer.GetIndexer(), -+ namespaceIndexer: namespaceInformer.GetIndexer(), -+ nodeIndexer: nodeInformer.GetIndexer(), - } - - c.hasSynced = func() bool { - return vmInformer.HasSynced() && vmiInformer.HasSynced() && podInformer.HasSynced() && - dataVolumeInformer.HasSynced() && cdiConfigInformer.HasSynced() && cdiInformer.HasSynced() && -- pvcInformer.HasSynced() && storageClassInformer.HasSynced() && storageProfileInformer.HasSynced() -+ pvcInformer.HasSynced() && storageClassInformer.HasSynced() && storageProfileInformer.HasSynced() && -+ allPodInformer.HasSynced() && namespaceInformer.HasSynced() && nodeInformer.HasSynced() - } - - _, err := vmiInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{ -@@ -221,6 +233,10 @@ type VMIController struct { - cidsMap *cidsMap - backendStorage *backendstorage.BackendStorage - hasSynced func() bool -+ -+ allPodIndexer cache.Indexer -+ namespaceIndexer cache.Indexer -+ nodeIndexer cache.Indexer - } - - func (c *VMIController) Run(threadiness int, stopCh <-chan struct{}) { -@@ -691,6 +707,10 @@ func (c *VMIController) updateStatus(vmi *virtv1.VirtualMachineInstance, pod *k8 - c.syncVolumesUpdate(vmiCopy) - } - -+ if err := c.syncNodePlacementCondition(vmiCopy, pod); err != nil { -+ return fmt.Errorf("failed to update condition %s", virtv1.VirtualMachineInstanceNodePlacementNotMatched) -+ } -+ - case vmi.IsScheduled(): - if !vmiPodExists { - vmiCopy.Status.Phase = virtv1.Failed -@@ -2416,6 +2436,172 @@ func (c *VMIController) syncVolumesUpdate(vmi *virtv1.VirtualMachineInstance) { - vmiConditions.UpdateCondition(vmi, &condition) - } - -+func (c *VMIController) syncNodePlacementCondition(vmi *virtv1.VirtualMachineInstance, pod *k8sv1.Pod) error { -+ status := k8sv1.ConditionFalse -+ templatePod, err := c.templateService.RenderLaunchManifest(vmi) -+ if err != nil { -+ return fmt.Errorf("failed to render pod manifest: %w", err) -+ } -+ changed, err := c.isChangedNodePlacement(pod, templatePod) -+ if err != nil { -+ return fmt.Errorf("could not verify if NodePlacement update is required: %w", err) -+ } -+ if changed { -+ matched, err := c.nodePlacementIsMatched(pod, templatePod) -+ if err != nil { -+ return fmt.Errorf("failed to verify if NodePlacement update is matched: %w", err) -+ } -+ if !matched { -+ status = k8sv1.ConditionTrue -+ } -+ } -+ c.syncNodePlacementNotMatchedCondition(vmi, status) -+ return nil -+} -+ -+func (c *VMIController) isChangedNodePlacement(pod, templatePod *k8sv1.Pod) (bool, error) { -+ if pod == nil || templatePod == nil { -+ return false, nil -+ } -+ -+ // when migration controller creating target pod. It will be created with PodAntiAffinity -+ { -+ var antiAffinityTerm *k8sv1.PodAffinityTerm -+ -+ if pod.Spec.Affinity != nil && -+ pod.Spec.Affinity.PodAntiAffinity != nil && -+ len(pod.Spec.Affinity.PodAntiAffinity.RequiredDuringSchedulingIgnoredDuringExecution) > 0 { -+ for _, rd := range pod.Spec.Affinity.PodAntiAffinity.RequiredDuringSchedulingIgnoredDuringExecution { -+ if rd.LabelSelector != nil { -+ if _, found := rd.LabelSelector.MatchLabels[virtv1.CreatedByLabel]; found { -+ antiAffinityTerm = rd.DeepCopy() -+ } -+ } -+ } -+ } -+ if antiAffinityTerm != nil { -+ antiAffinityRule := &k8sv1.PodAntiAffinity{ -+ RequiredDuringSchedulingIgnoredDuringExecution: []k8sv1.PodAffinityTerm{*antiAffinityTerm}, -+ } -+ if templatePod.Spec.Affinity == nil { -+ templatePod.Spec.Affinity = &k8sv1.Affinity{ -+ PodAntiAffinity: antiAffinityRule, -+ } -+ } else if templatePod.Spec.Affinity.PodAntiAffinity == nil { -+ templatePod.Spec.Affinity.PodAntiAffinity = antiAffinityRule -+ } else { -+ templatePod.Spec.Affinity.PodAntiAffinity.RequiredDuringSchedulingIgnoredDuringExecution = append(templatePod.Spec.Affinity.PodAntiAffinity.RequiredDuringSchedulingIgnoredDuringExecution, *antiAffinityTerm) -+ } -+ } -+ } -+ -+ return !equality.Semantic.DeepEqual(pod.Spec.NodeSelector, templatePod.Spec.NodeSelector) || -+ !equality.Semantic.DeepEqual(pod.Spec.Affinity, templatePod.Spec.Affinity), nil -+} -+ -+func (c *VMIController) nodePlacementIsMatched(pod, templatePod *k8sv1.Pod) (bool, error) { -+ if pod == nil || templatePod == nil { -+ return false, fmt.Errorf("pod or templatePod must not be nil") -+ } -+ templatePod.Namespace = pod.Namespace -+ templatePod.Name = pod.Name -+ obj, exist, err := c.nodeIndexer.GetByKey(pod.Spec.NodeName) -+ if err != nil { -+ return false, err -+ } -+ node := obj.(*k8sv1.Node) -+ if !exist || node == nil { -+ return false, fmt.Errorf("not found node %s", pod.Spec.NodeName) -+ } -+ -+ requiredNodeSelectorAndAffinity := affinity.GetRequiredNodeAffinity(templatePod) -+ match, err := requiredNodeSelectorAndAffinity.Match(node) -+ if err != nil { -+ return false, fmt.Errorf("failed to match required node selector and affinity: %w", err) -+ } -+ if !match { -+ return false, nil -+ } -+ -+ pods, err := c.listPodsByNode(pod.Spec.NodeName) -+ if err != nil { -+ return false, err -+ } -+ -+ podNamespaces := make(map[string]struct{}) -+ for _, p := range pods { -+ podNamespaces[p.GetNamespace()] = struct{}{} -+ } -+ allNamespaces := c.namespaceIndexer.List() -+ namespaceLabels := make(map[string]labels.Set, len(podNamespaces)) -+ for _, o := range allNamespaces { -+ ns := o.(*k8sv1.Namespace) -+ if _, ok := podNamespaces[ns.GetName()]; ok { -+ namespaceLabels[ns.GetName()] = ns.GetLabels() -+ } -+ } -+ -+ podAffinityTerms, err := affinity.GetAffinityTerms(templatePod, affinity.GetPodAffinityTerms(templatePod.Spec.Affinity)) -+ if err != nil { -+ return false, err -+ } -+ podAntiAffinityTerms, err := affinity.GetAffinityTerms(templatePod, affinity.GetPodAntiAffinityTerms(templatePod.Spec.Affinity)) -+ if err != nil { -+ return false, err -+ } -+ -+ var ( -+ podMatchedByPodAffinityFound bool -+ ) -+ -+ for _, p := range pods { -+ if p.GetUID() == pod.GetUID() { -+ continue -+ } -+ if p.Status.Phase == k8sv1.PodSucceeded || p.Status.Phase == k8sv1.PodFailed { -+ continue -+ } -+ nsLabels := namespaceLabels[p.GetNamespace()] -+ -+ // If at least one matches the podAffinity, then node placement is suitable. -+ if !podMatchedByPodAffinityFound && affinity.MatchPodAffinityTerms(podAffinityTerms, p, nsLabels) { -+ podMatchedByPodAffinityFound = true -+ } -+ // If at least one matches the podAntiAffinity, then node placement is not suitable. return false -+ if affinity.MatchPodAntiAffinityTerms(podAntiAffinityTerms, p, nsLabels) { -+ return false, nil -+ } -+ } -+ -+ return podMatchedByPodAffinityFound, nil -+} -+ -+// listPodsByNode takes a node and returns all Pods from the pod cache which run on this node -+func (c *VMIController) listPodsByNode(node string) ([]*k8sv1.Pod, error) { -+ objs, err := c.allPodIndexer.ByIndex("node", node) -+ if err != nil { -+ return nil, err -+ } -+ pods := make([]*k8sv1.Pod, 0, len(objs)) -+ for _, obj := range objs { -+ pod, ok := obj.(*k8sv1.Pod) -+ if ok { -+ pods = append(pods, pod) -+ } -+ } -+ return pods, nil -+} -+ -+func (c *VMIController) syncNodePlacementNotMatchedCondition(vmi *virtv1.VirtualMachineInstance, status k8sv1.ConditionStatus) { -+ vmiConditions := controller.NewVirtualMachineInstanceConditionManager() -+ condition := virtv1.VirtualMachineInstanceCondition{ -+ Type: virtv1.VirtualMachineInstanceNodePlacementNotMatched, -+ Status: status, -+ LastTransitionTime: v1.Now(), -+ } -+ vmiConditions.UpdateCondition(vmi, &condition) -+} -+ - func (c *VMIController) aggregateDataVolumesConditions(vmiCopy *virtv1.VirtualMachineInstance, dvs []*cdiv1.DataVolume) { - if len(dvs) == 0 { - return -diff --git a/pkg/virt-controller/watch/workload-updater/workload-updater.go b/pkg/virt-controller/watch/workload-updater/workload-updater.go -index a7d0f76e24..e9205679de 100644 ---- a/pkg/virt-controller/watch/workload-updater/workload-updater.go -+++ b/pkg/virt-controller/watch/workload-updater/workload-updater.go -@@ -214,7 +214,7 @@ func (c *WorkloadUpdateController) updateVmi(_, obj interface{}) { - return - } - -- if !(isHotplugInProgress(vmi) || isVolumesUpdateInProgress(vmi)) || -+ if !(isHotplugInProgress(vmi) || isVolumesUpdateInProgress(vmi) || isNodePlacementInProgress(vmi)) || - migrationutils.IsMigrating(vmi) { - return - } -@@ -324,6 +324,11 @@ func isVolumesUpdateInProgress(vmi *virtv1.VirtualMachineInstance) bool { - virtv1.VirtualMachineInstanceVolumesChange, k8sv1.ConditionTrue) - } - -+func isNodePlacementInProgress(vmi *virtv1.VirtualMachineInstance) bool { -+ return controller.NewVirtualMachineInstanceConditionManager().HasConditionWithStatus(vmi, -+ virtv1.VirtualMachineInstanceNodePlacementNotMatched, k8sv1.ConditionTrue) -+} -+ - func (c *WorkloadUpdateController) doesRequireMigration(vmi *virtv1.VirtualMachineInstance) bool { - if vmi.IsFinal() || migrationutils.IsMigrating(vmi) { - return false -@@ -337,6 +342,9 @@ func (c *WorkloadUpdateController) doesRequireMigration(vmi *virtv1.VirtualMachi - if isVolumesUpdateInProgress(vmi) { - return true - } -+ if isNodePlacementInProgress(vmi) { -+ return true -+ } - - return false - } -@@ -352,6 +360,9 @@ func (c *WorkloadUpdateController) shouldAbortMigration(vmi *virtv1.VirtualMachi - if isVolumesUpdateInProgress(vmi) { - return false - } -+ if isNodePlacementInProgress(vmi) { -+ return false -+ } - if vmi.Status.MigrationState != nil && vmi.Status.MigrationState.TargetNodeDomainReadyTimestamp != nil { - return false - } -diff --git a/pkg/virt-handler/vm.go b/pkg/virt-handler/vm.go -index cdc1f815c3..24352cf6e9 100644 ---- a/pkg/virt-handler/vm.go -+++ b/pkg/virt-handler/vm.go -@@ -3468,6 +3468,7 @@ func (d *VirtualMachineController) finalizeMigration(vmi *v1.VirtualMachineInsta - d.recorder.Event(vmi, k8sv1.EventTypeWarning, err.Error(), "failed to update guest memory") - } - removeMigratedVolumes(vmi) -+ finalizeNodePlacement(vmi) - - options := &cmdv1.VirtualMachineOptions{} - options.InterfaceMigration = domainspec.BindingMigrationByInterfaceName(vmi.Spec.Domain.Devices.Interfaces, d.clusterConfig.GetNetworkBindings()) -@@ -3684,6 +3685,10 @@ func (d *VirtualMachineController) hotplugMemory(vmi *v1.VirtualMachineInstance, - return nil - } - -+func finalizeNodePlacement(vmi *v1.VirtualMachineInstance) { -+ controller.NewVirtualMachineInstanceConditionManager().RemoveCondition(vmi, v1.VirtualMachineInstanceNodePlacementNotMatched) -+} -+ - func removeMigratedVolumes(vmi *v1.VirtualMachineInstance) { - vmiConditions := controller.NewVirtualMachineInstanceConditionManager() - vmiConditions.RemoveCondition(vmi, v1.VirtualMachineInstanceVolumesChange) -diff --git a/staging/src/kubevirt.io/api/core/v1/types.go b/staging/src/kubevirt.io/api/core/v1/types.go -index 7aa814d8f1..841387d304 100644 ---- a/staging/src/kubevirt.io/api/core/v1/types.go -+++ b/staging/src/kubevirt.io/api/core/v1/types.go -@@ -568,6 +568,9 @@ const ( - - // Summarizes that all the DataVolumes attached to the VMI are Ready or not - VirtualMachineInstanceDataVolumesReady VirtualMachineInstanceConditionType = "DataVolumesReady" -+ -+ // Indicates that the VMI has affinity or nodeSelector changes -+ VirtualMachineInstanceNodePlacementNotMatched VirtualMachineInstanceConditionType = "NodePlacementNotMatched" - ) - - // These are valid reasons for VMI conditions. diff --git a/images/virt-artifact/patches/028-inject-placement-anynode.patch b/images/virt-artifact/patches/028-inject-placement-anynode.patch deleted file mode 100644 index 91ce2d702b..0000000000 --- a/images/virt-artifact/patches/028-inject-placement-anynode.patch +++ /dev/null @@ -1,26 +0,0 @@ -diff --git a/pkg/virt-operator/resource/apply/apps.go b/pkg/virt-operator/resource/apply/apps.go -index 86a7e9cb5d..8554de9a05 100644 ---- a/pkg/virt-operator/resource/apply/apps.go -+++ b/pkg/virt-operator/resource/apply/apps.go -@@ -51,7 +51,7 @@ func (r *Reconciler) syncDeployment(origDeployment *appsv1.Deployment) (*appsv1. - - injectOperatorMetadata(kv, &deployment.ObjectMeta, imageTag, imageRegistry, id, true) - injectOperatorMetadata(kv, &deployment.Spec.Template.ObjectMeta, imageTag, imageRegistry, id, false) -- InjectPlacementMetadata(kv.Spec.Infra, &deployment.Spec.Template.Spec, RequireControlPlanePreferNonWorker) -+ InjectPlacementMetadata(kv.Spec.Infra, &deployment.Spec.Template.Spec, AnyNode) - - if kv.Spec.Infra != nil && kv.Spec.Infra.Replicas != nil { - replicas := int32(*kv.Spec.Infra.Replicas) -diff --git a/pkg/virt-operator/strategy_job.go b/pkg/virt-operator/strategy_job.go -index df94c43bb1..b7ca869207 100644 ---- a/pkg/virt-operator/strategy_job.go -+++ b/pkg/virt-operator/strategy_job.go -@@ -111,7 +111,7 @@ func (c *KubeVirtController) generateInstallStrategyJob(infraPlacement *v1.Compo - }, - } - -- apply.InjectPlacementMetadata(infraPlacement, &job.Spec.Template.Spec, apply.RequireControlPlanePreferNonWorker) -+ apply.InjectPlacementMetadata(infraPlacement, &job.Spec.Template.Spec, apply.AnyNode) - env := job.Spec.Template.Spec.Containers[0].Env - extraEnv := util.NewEnvVarMap(config.GetExtraEnv()) - job.Spec.Template.Spec.Containers[0].Env = append(env, *extraEnv...) diff --git a/images/virt-artifact/patches/029-use-OFVM_CODE-for-linux.patch b/images/virt-artifact/patches/029-use-OFVM_CODE-for-linux.patch deleted file mode 100644 index 6bd8e1d06a..0000000000 --- a/images/virt-artifact/patches/029-use-OFVM_CODE-for-linux.patch +++ /dev/null @@ -1,43 +0,0 @@ -diff --git a/pkg/virt-launcher/virtwrap/manager.go b/pkg/virt-launcher/virtwrap/manager.go -index 2513ad62a8..4a1d22de46 100644 ---- a/pkg/virt-launcher/virtwrap/manager.go -+++ b/pkg/virt-launcher/virtwrap/manager.go -@@ -966,17 +966,36 @@ func (l *LibvirtDomainManager) generateConverterContext(vmi *v1.VirtualMachineIn - - var efiConf *converter.EFIConfiguration - if vmi.IsBootloaderEFI() { -+ const ann = "virtualization.deckhouse.io/os-type" -+ const windows = "Windows" -+ - secureBoot := vmi.Spec.Domain.Firmware.Bootloader.EFI.SecureBoot == nil || *vmi.Spec.Domain.Firmware.Bootloader.EFI.SecureBoot - sev := kutil.IsSEVVMI(vmi) - -+ forceCCEFI := false -+ if !sev { -+ if a := vmi.GetAnnotations()[ann]; a != windows { -+ /* -+ Kubevirt uses OVFM_CODE.secboot.fd in 2 combinations: OVFM_CODE.secboot.fd + OVFM_VARS.secboot.fd when secboot is enabled and OVFM_CODE.secboot.fd + OVFM_VARS.fd when secboot is disabled. -+ It works fine with original CentOS based virt-launcher in both secboot modes. -+ We use ALTLinux based virt-launcher, and it fails to start Linux VM with more than 12 CPUs in secboot disabled mode. -+ -+ Kubevirt uses flags to detect firmware combinations in converter. -+ EFIConfiguration, so we can't set needed files directly. -+ But there is combination for SEV: OVFM_CODE.cc.fd + OVMF_VARS.fd that works for Linux, because OVFM_CODE.cc.fd is actually a symlink to OVFM_CODE.fd. -+ So, we set true for the second flag to force OVFM_CODE.cc.fd + OVMF_VARS.fd for non-Windows virtual machines. -+ */ -+ forceCCEFI = true -+ } -+ } - if !l.efiEnvironment.Bootable(secureBoot, sev) { - log.Log.Errorf("EFI OVMF roms missing for booting in EFI mode with SecureBoot=%v, SEV=%v", secureBoot, sev) - return nil, fmt.Errorf("EFI OVMF roms missing for booting in EFI mode with SecureBoot=%v, SEV=%v", secureBoot, sev) - } - - efiConf = &converter.EFIConfiguration{ -- EFICode: l.efiEnvironment.EFICode(secureBoot, sev), -- EFIVars: l.efiEnvironment.EFIVars(secureBoot, sev), -+ EFICode: l.efiEnvironment.EFICode(secureBoot, sev || forceCCEFI), -+ EFIVars: l.efiEnvironment.EFIVars(secureBoot, sev || forceCCEFI), - SecureLoader: secureBoot, - } - } diff --git a/images/virt-artifact/patches/030-prevent-adding-node-selector-for-dvp-generic-cpu-model.patch b/images/virt-artifact/patches/030-prevent-adding-node-selector-for-dvp-generic-cpu-model.patch deleted file mode 100644 index 6975b93d6f..0000000000 --- a/images/virt-artifact/patches/030-prevent-adding-node-selector-for-dvp-generic-cpu-model.patch +++ /dev/null @@ -1,44 +0,0 @@ -diff --git a/pkg/virt-controller/services/nodeselectorrenderer.go b/pkg/virt-controller/services/nodeselectorrenderer.go -index 390f359d2a..c21caf97dd 100644 ---- a/pkg/virt-controller/services/nodeselectorrenderer.go -+++ b/pkg/virt-controller/services/nodeselectorrenderer.go -@@ -23,6 +23,9 @@ type NodeSelectorRenderer struct { - - type NodeSelectorRendererOption func(renderer *NodeSelectorRenderer) - -+// DeckhouseVirtualizationPlatformGenericCPUModel is a name of additional empty CPU model for Discovery type of VMClass. -+const DeckhouseVirtualizationPlatformGenericCPUModel = "kvm64" -+ - func NewNodeSelectorRenderer( - vmiNodeSelectors map[string]string, - clusterWideConfNodeSelectors map[string]string, -@@ -51,7 +54,8 @@ func (nsr *NodeSelectorRenderer) Render() map[string]string { - if nsr.hyperv { - maps.Copy(nsr.podNodeSelectors, hypervNodeSelectors(nsr.vmiFeatures)) - } -- if nsr.cpuModelLabel != "" && nsr.cpuModelLabel != cpuModelLabel(v1.CPUModeHostModel) && nsr.cpuModelLabel != cpuModelLabel(v1.CPUModeHostPassthrough) { -+ // Prevent adding node selector for host-model, host-passthrough and an empty CPU model. -+ if nsr.cpuModelLabel != "" && nsr.cpuModelLabel != cpuModelLabel(v1.CPUModeHostModel) && nsr.cpuModelLabel != cpuModelLabel(v1.CPUModeHostPassthrough) && nsr.cpuModelLabel != cpuModelLabel(DeckhouseVirtualizationPlatformGenericCPUModel) { - nsr.enableSelectorLabel(nsr.cpuModelLabel) - } - for _, cpuFeatureLabel := range nsr.cpuFeatureLabels { -diff --git a/pkg/virt-launcher/virtwrap/live-migration-source.go b/pkg/virt-launcher/virtwrap/live-migration-source.go -index 5cc14a1f85..6bd0ba3d9d 100644 ---- a/pkg/virt-launcher/virtwrap/live-migration-source.go -+++ b/pkg/virt-launcher/virtwrap/live-migration-source.go -@@ -230,6 +230,15 @@ func migratableDomXML(dom cli.VirDomain, vmi *v1.VirtualMachineInstance, domSpec - return "", err - } - -+ // Put back common model if specified in VMI. -+ vmiCPU := vmi.Spec.Domain.CPU -+ if vmiCPU != nil && vmiCPU.Model == "kvm64" { -+ if domcfg.CPU.Model != nil { -+ domcfg.CPU.Model.Value = vmiCPU.Model -+ domcfg.CPU.Model.Fallback = "allow" -+ } -+ } -+ - return domcfg.Marshal() - } - diff --git a/images/virt-artifact/patches/031-hotplug-container-disk.patch b/images/virt-artifact/patches/031-hotplug-container-disk.patch deleted file mode 100644 index f937e4a87b..0000000000 --- a/images/virt-artifact/patches/031-hotplug-container-disk.patch +++ /dev/null @@ -1,2429 +0,0 @@ -diff --git a/api/openapi-spec/swagger.json b/api/openapi-spec/swagger.json -index c4822a0448..d6bb534249 100644 ---- a/api/openapi-spec/swagger.json -+++ b/api/openapi-spec/swagger.json -@@ -12951,6 +12951,9 @@ - "image" - ], - "properties": { -+ "hotpluggable": { -+ "type": "boolean" -+ }, - "image": { - "description": "Image is the name of the image with the embedded disk.", - "type": "string", -@@ -13973,6 +13976,9 @@ - "description": "HotplugVolumeSource Represents the source of a volume to mount which are capable of being hotplugged on a live running VMI. Only one of its members may be specified.", - "type": "object", - "properties": { -+ "containerDisk": { -+ "$ref": "#/definitions/v1.ContainerDiskSource" -+ }, - "dataVolume": { - "description": "DataVolume represents the dynamic creation a PVC for this volume as well as the process of populating that PVC with a disk image.", - "$ref": "#/definitions/v1.DataVolumeSource" -diff --git a/cmd/container-disk-v2alpha/main.c b/cmd/container-disk-v2alpha/main.c -index ba855e574b..8ed76d8710 100644 ---- a/cmd/container-disk-v2alpha/main.c -+++ b/cmd/container-disk-v2alpha/main.c -@@ -179,4 +179,4 @@ int main(int argc, char **argv) { - } - - socket_check(fd, (void *)copy_path); --} -+} -\ No newline at end of file -diff --git a/cmd/virt-chroot/main.go b/cmd/virt-chroot/main.go -index e28daa07c7..7a69b7451b 100644 ---- a/cmd/virt-chroot/main.go -+++ b/cmd/virt-chroot/main.go -@@ -20,6 +20,7 @@ var ( - cpuTime uint64 - memoryBytes uint64 - targetUser string -+ targetUserID int - ) - - func init() { -@@ -51,7 +52,12 @@ func main() { - - // Looking up users needs resources, let's do it before we set rlimits. - var u *user.User -- if targetUser != "" { -+ if targetUserID >= 0 { -+ _, _, errno := syscall.Syscall(syscall.SYS_SETUID, uintptr(targetUserID), 0, 0) -+ if errno != 0 { -+ return fmt.Errorf("failed to switch to user: %d. errno: %d", targetUserID, errno) -+ } -+ } else if targetUser != "" { - var err error - u, err = user.Lookup(targetUser) - if err != nil { -@@ -116,6 +122,7 @@ func main() { - rootCmd.PersistentFlags().Uint64Var(&memoryBytes, "memory", 0, "memory in bytes for the process") - rootCmd.PersistentFlags().StringVar(&mntNamespace, "mount", "", "mount namespace to use") - rootCmd.PersistentFlags().StringVar(&targetUser, "user", "", "switch to this targetUser to e.g. drop privileges") -+ rootCmd.PersistentFlags().IntVar(&targetUserID, "userid", -1, "switch to this targetUser to e.g. drop privileges") - - execCmd := &cobra.Command{ - Use: "exec", -@@ -136,16 +143,39 @@ func main() { - Args: cobra.MinimumNArgs(2), - RunE: func(cmd *cobra.Command, args []string) error { - var mntOpts uint = 0 -+ var dataOpts []string - - fsType := cmd.Flag("type").Value.String() - mntOptions := cmd.Flag("options").Value.String() -+ var ( -+ uid = -1 -+ gid = -1 -+ ) - for _, opt := range strings.Split(mntOptions, ",") { - opt = strings.TrimSpace(opt) -- switch opt { -- case "ro": -+ switch { -+ case opt == "ro": - mntOpts = mntOpts | syscall.MS_RDONLY -- case "bind": -+ case opt == "bind": - mntOpts = mntOpts | syscall.MS_BIND -+ case opt == "remount": -+ mntOpts = mntOpts | syscall.MS_REMOUNT -+ case strings.HasPrefix(opt, "uid="): -+ uidS := strings.TrimPrefix(opt, "uid=") -+ uidI, err := strconv.Atoi(uidS) -+ if err != nil { -+ return fmt.Errorf("failed to parse uid: %w", err) -+ } -+ uid = uidI -+ dataOpts = append(dataOpts, opt) -+ case strings.HasPrefix(opt, "gid="): -+ gidS := strings.TrimPrefix(opt, "gid=") -+ gidI, err := strconv.Atoi(gidS) -+ if err != nil { -+ return fmt.Errorf("failed to parse gid: %w", err) -+ } -+ gid = gidI -+ dataOpts = append(dataOpts, opt) - default: - return fmt.Errorf("mount option %s is not supported", opt) - } -@@ -168,8 +198,17 @@ func main() { - return fmt.Errorf("mount target invalid: %v", err) - } - defer targetFile.Close() -- -- return syscall.Mount(sourceFile.SafePath(), targetFile.SafePath(), fsType, uintptr(mntOpts), "") -+ if uid >= 0 && gid >= 0 { -+ err = os.Chown(targetFile.SafePath(), uid, gid) -+ if err != nil { -+ return fmt.Errorf("chown target failed: %w", err) -+ } -+ } -+ var data string -+ if len(dataOpts) > 0 { -+ data = strings.Join(dataOpts, ",") -+ } -+ return syscall.Mount(sourceFile.SafePath(), targetFile.SafePath(), fsType, uintptr(mntOpts), data) - }, - } - mntCmd.Flags().StringP("options", "o", "", "comma separated list of mount options") -diff --git a/manifests/generated/kv-resource.yaml b/manifests/generated/kv-resource.yaml -index 66d1b01dbf..43e36b7195 100644 ---- a/manifests/generated/kv-resource.yaml -+++ b/manifests/generated/kv-resource.yaml -@@ -3307,9 +3307,6 @@ spec: - - jsonPath: .status.phase - name: Phase - type: string -- deprecated: true -- deprecationWarning: kubevirt.io/v1alpha3 is now deprecated and will be removed -- in a future release. - name: v1alpha3 - schema: - openAPIV3Schema: -diff --git a/manifests/generated/operator-csv.yaml.in b/manifests/generated/operator-csv.yaml.in -index 400d118024..05ee099c67 100644 ---- a/manifests/generated/operator-csv.yaml.in -+++ b/manifests/generated/operator-csv.yaml.in -@@ -605,6 +605,13 @@ spec: - - '*' - verbs: - - '*' -+ - apiGroups: -+ - subresources.virtualization.deckhouse.io -+ resources: -+ - virtualmachines/addvolume -+ - virtualmachines/removevolume -+ verbs: -+ - update - - apiGroups: - - subresources.kubevirt.io - resources: -diff --git a/manifests/generated/rbac-operator.authorization.k8s.yaml.in b/manifests/generated/rbac-operator.authorization.k8s.yaml.in -index 10dbb92269..1ccc9e9fa7 100644 ---- a/manifests/generated/rbac-operator.authorization.k8s.yaml.in -+++ b/manifests/generated/rbac-operator.authorization.k8s.yaml.in -@@ -143,7 +143,7 @@ kind: RoleBinding - metadata: - labels: - kubevirt.io: "" -- name: kubevirt-operator-rolebinding -+ name: kubevirt-operator - namespace: {{.Namespace}} - roleRef: - apiGroup: rbac.authorization.k8s.io -@@ -607,6 +607,13 @@ rules: - - '*' - verbs: - - '*' -+- apiGroups: -+ - subresources.virtualization.deckhouse.io -+ resources: -+ - virtualmachines/addvolume -+ - virtualmachines/removevolume -+ verbs: -+ - update - - apiGroups: - - subresources.kubevirt.io - resources: -diff --git a/pkg/container-disk/container-disk.go b/pkg/container-disk/container-disk.go -index 3251d04787..83ecab813d 100644 ---- a/pkg/container-disk/container-disk.go -+++ b/pkg/container-disk/container-disk.go -@@ -30,6 +30,7 @@ import ( - - kubev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/resource" -+ "k8s.io/apimachinery/pkg/types" - - "kubevirt.io/kubevirt/pkg/safepath" - -@@ -47,8 +48,10 @@ var containerDiskOwner = "qemu" - var podsBaseDir = util.KubeletPodsDir - - var mountBaseDir = filepath.Join(util.VirtShareDir, "/container-disks") -+var hotplugBaseDir = filepath.Join(util.VirtShareDir, "/hotplug-disks") - - type SocketPathGetter func(vmi *v1.VirtualMachineInstance, volumeIndex int) (string, error) -+type HotplugSocketPathGetter func(vmi *v1.VirtualMachineInstance, volumeName string, sourceUID types.UID) (string, error) - type KernelBootSocketPathGetter func(vmi *v1.VirtualMachineInstance) (string, error) - - const KernelBootName = "kernel-boot" -@@ -107,6 +110,10 @@ func GetDiskTargetPathFromLauncherView(volumeIndex int) string { - return filepath.Join(mountBaseDir, GetDiskTargetName(volumeIndex)) - } - -+func GetHotplugContainerDiskTargetPathFromLauncherView(volumeName string) string { -+ return filepath.Join(hotplugBaseDir, fmt.Sprintf("%s.img", volumeName)) -+} -+ - func GetKernelBootArtifactPathFromLauncherView(artifact string) string { - artifactBase := filepath.Base(artifact) - return filepath.Join(mountBaseDir, KernelBootName, artifactBase) -@@ -170,6 +177,27 @@ func NewSocketPathGetter(baseDir string) SocketPathGetter { - } - } - -+func NewHotplugSocketPathGetter(baseDir string) HotplugSocketPathGetter { -+ return func(vmi *v1.VirtualMachineInstance, volumeName string, sourceUID types.UID) (string, error) { -+ for _, v := range vmi.Status.VolumeStatus { -+ if v.Name == volumeName && v.HotplugVolume != nil && v.ContainerDiskVolume != nil { -+ uid := string(sourceUID) -+ if uid == "" { -+ uid = string(v.HotplugVolume.AttachPodUID) -+ } -+ basePath := getHotplugContainerDiskSocketBasePath(baseDir, uid) -+ socketPath := filepath.Join(basePath, fmt.Sprintf("hotplug-container-disk-%s.sock", volumeName)) -+ exists, _ := diskutils.FileExists(socketPath) -+ if exists { -+ return socketPath, nil -+ } -+ } -+ } -+ -+ return "", fmt.Errorf("container disk socket path not found for vmi \"%s\"", vmi.Name) -+ } -+} -+ - // NewKernelBootSocketPathGetter get the socket pat of the kernel-boot containerDisk. For testing a baseDir - // can be provided which can for instance point to /tmp. - func NewKernelBootSocketPathGetter(baseDir string) KernelBootSocketPathGetter { -@@ -278,7 +306,7 @@ func generateContainersHelper(vmi *v1.VirtualMachineInstance, config *virtconfig - } - - func generateContainerFromVolume(vmi *v1.VirtualMachineInstance, config *virtconfig.ClusterConfig, imageIDs map[string]string, podVolumeName, binVolumeName string, isInit, isKernelBoot bool, volume *v1.Volume, volumeIdx int) *kubev1.Container { -- if volume.ContainerDisk == nil { -+ if volume.ContainerDisk == nil || volume.ContainerDisk.Hotpluggable { - return nil - } - -@@ -378,11 +406,34 @@ func CreateEphemeralImages( - // for each disk that requires it. - - for i, volume := range vmi.Spec.Volumes { -- if volume.VolumeSource.ContainerDisk != nil { -+ if volume.VolumeSource.ContainerDisk != nil && !volume.VolumeSource.ContainerDisk.Hotpluggable { -+ info, _ := disksInfo[volume.Name] -+ if info == nil { -+ return fmt.Errorf("no disk info provided for volume %s", volume.Name) -+ } -+ if backingFile, err := GetDiskTargetPartFromLauncherView(i); err != nil { -+ return err -+ } else if err := diskCreator.CreateBackedImageForVolume(volume, backingFile, info.Format); err != nil { -+ return err -+ } -+ } -+ } -+ -+ return nil -+} -+ -+func CreateEphemeralImagesForHotplug( -+ vmi *v1.VirtualMachineInstance, -+ diskCreator ephemeraldisk.EphemeralDiskCreatorInterface, -+ disksInfo map[string]*DiskInfo, -+) error { -+ for i, volume := range vmi.Spec.Volumes { -+ if volume.VolumeSource.ContainerDisk != nil && volume.VolumeSource.ContainerDisk.Hotpluggable { - info, _ := disksInfo[volume.Name] - if info == nil { - return fmt.Errorf("no disk info provided for volume %s", volume.Name) - } -+ - if backingFile, err := GetDiskTargetPartFromLauncherView(i); err != nil { - return err - } else if err := diskCreator.CreateBackedImageForVolume(volume, backingFile, info.Format); err != nil { -@@ -398,6 +449,10 @@ func getContainerDiskSocketBasePath(baseDir, podUID string) string { - return fmt.Sprintf("%s/pods/%s/volumes/kubernetes.io~empty-dir/container-disks", baseDir, podUID) - } - -+func getHotplugContainerDiskSocketBasePath(baseDir, podUID string) string { -+ return fmt.Sprintf("%s/pods/%s/volumes/kubernetes.io~empty-dir/hotplug-container-disks", baseDir, podUID) -+} -+ - // ExtractImageIDsFromSourcePod takes the VMI and its source pod to determine the exact image used by containerdisks and boot container images, - // which is recorded in the status section of a started pod; if the status section does not contain this info the tag is used. - // It returns a map where the key is the vlume name and the value is the imageID -diff --git a/pkg/container-disk/util.go b/pkg/container-disk/util.go -new file mode 100644 -index 0000000000..293ca1d9b4 ---- /dev/null -+++ b/pkg/container-disk/util.go -@@ -0,0 +1,10 @@ -+package containerdisk -+ -+import virtv1 "kubevirt.io/api/core/v1" -+ -+func IsHotplugContainerDisk(v *virtv1.Volume) bool { -+ return v != nil && IsHotplugContainerDiskSource(v.VolumeSource) -+} -+func IsHotplugContainerDiskSource(vs virtv1.VolumeSource) bool { -+ return vs.ContainerDisk != nil && vs.ContainerDisk.Hotpluggable -+} -diff --git a/pkg/controller/controller.go b/pkg/controller/controller.go -index 490cc445ef..96c48937e7 100644 ---- a/pkg/controller/controller.go -+++ b/pkg/controller/controller.go -@@ -38,6 +38,8 @@ import ( - v1 "kubevirt.io/api/core/v1" - "kubevirt.io/client-go/log" - cdiv1 "kubevirt.io/containerized-data-importer-api/pkg/apis/core/v1beta1" -+ -+ container_disk "kubevirt.io/kubevirt/pkg/container-disk" - ) - - const ( -@@ -278,6 +280,10 @@ func ApplyVolumeRequestOnVMISpec(vmiSpec *v1.VirtualMachineInstanceSpec, request - dvSource := request.AddVolumeOptions.VolumeSource.DataVolume.DeepCopy() - dvSource.Hotpluggable = true - newVolume.VolumeSource.DataVolume = dvSource -+ } else if request.AddVolumeOptions.VolumeSource.ContainerDisk != nil { -+ containerDiskSource := request.AddVolumeOptions.VolumeSource.ContainerDisk.DeepCopy() -+ containerDiskSource.Hotpluggable = true -+ newVolume.VolumeSource.ContainerDisk = containerDiskSource - } - - vmiSpec.Volumes = append(vmiSpec.Volumes, newVolume) -@@ -444,6 +450,9 @@ func VMIHasHotplugVolumes(vmi *v1.VirtualMachineInstance) bool { - if volume.PersistentVolumeClaim != nil && volume.PersistentVolumeClaim.Hotpluggable { - return true - } -+ if volume.ContainerDisk != nil && volume.ContainerDisk.Hotpluggable { -+ return true -+ } - } - return false - } -@@ -557,7 +566,7 @@ func GetHotplugVolumes(vmi *v1.VirtualMachineInstance, virtlauncherPod *k8sv1.Po - podVolumeMap[podVolume.Name] = podVolume - } - for _, vmiVolume := range vmiVolumes { -- if _, ok := podVolumeMap[vmiVolume.Name]; !ok && (vmiVolume.DataVolume != nil || vmiVolume.PersistentVolumeClaim != nil || vmiVolume.MemoryDump != nil) { -+ if _, ok := podVolumeMap[vmiVolume.Name]; !ok && (vmiVolume.DataVolume != nil || vmiVolume.PersistentVolumeClaim != nil || vmiVolume.MemoryDump != nil || container_disk.IsHotplugContainerDisk(&vmiVolume)) { - hotplugVolumes = append(hotplugVolumes, vmiVolume.DeepCopy()) - } - } -diff --git a/pkg/storage/types/pvc.go b/pkg/storage/types/pvc.go -index c8f387db16..81c80c260f 100644 ---- a/pkg/storage/types/pvc.go -+++ b/pkg/storage/types/pvc.go -@@ -144,6 +144,9 @@ func GetPVCsFromVolumes(volumes []virtv1.Volume) map[string]string { - func VirtVolumesToPVCMap(volumes []*virtv1.Volume, pvcStore cache.Store, namespace string) (map[string]*k8sv1.PersistentVolumeClaim, error) { - volumeNamesPVCMap := make(map[string]*k8sv1.PersistentVolumeClaim) - for _, volume := range volumes { -+ if volume.ContainerDisk != nil { -+ continue -+ } - claimName := PVCNameFromVirtVolume(volume) - if claimName == "" { - return nil, fmt.Errorf("volume %s is not a PVC or Datavolume", volume.Name) -@@ -280,6 +283,9 @@ func IsHotplugVolume(vol *virtv1.Volume) bool { - if volSrc.MemoryDump != nil && volSrc.MemoryDump.PersistentVolumeClaimVolumeSource.Hotpluggable { - return true - } -+ if volSrc.ContainerDisk != nil && volSrc.ContainerDisk.Hotpluggable { -+ return true -+ } - - return false - } -diff --git a/pkg/virt-api/rest/subresource.go b/pkg/virt-api/rest/subresource.go -index b5d62f5af5..6a3e2b4143 100644 ---- a/pkg/virt-api/rest/subresource.go -+++ b/pkg/virt-api/rest/subresource.go -@@ -1004,7 +1004,9 @@ func addVolumeRequestExists(request v1.VirtualMachineVolumeRequest, name string) - } - - func volumeHotpluggable(volume v1.Volume) bool { -- return (volume.DataVolume != nil && volume.DataVolume.Hotpluggable) || (volume.PersistentVolumeClaim != nil && volume.PersistentVolumeClaim.Hotpluggable) -+ return (volume.DataVolume != nil && volume.DataVolume.Hotpluggable) || -+ (volume.PersistentVolumeClaim != nil && volume.PersistentVolumeClaim.Hotpluggable) || -+ (volume.ContainerDisk != nil && volume.ContainerDisk.Hotpluggable) - } - - func volumeNameExists(volume v1.Volume, volumeName string) bool { -@@ -1018,12 +1020,16 @@ func volumeSourceName(volumeSource *v1.HotplugVolumeSource) string { - if volumeSource.PersistentVolumeClaim != nil { - return volumeSource.PersistentVolumeClaim.ClaimName - } -+ if volumeSource.ContainerDisk != nil { -+ return volumeSource.ContainerDisk.Image -+ } - return "" - } - - func volumeSourceExists(volume v1.Volume, volumeName string) bool { - return (volume.DataVolume != nil && volume.DataVolume.Name == volumeName) || -- (volume.PersistentVolumeClaim != nil && volume.PersistentVolumeClaim.ClaimName == volumeName) -+ (volume.PersistentVolumeClaim != nil && volume.PersistentVolumeClaim.ClaimName == volumeName) || -+ (volume.ContainerDisk != nil && volume.ContainerDisk.Image == volumeName) - } - - func volumeExists(volume v1.Volume, volumeName string) bool { -@@ -1125,6 +1131,8 @@ func (app *SubresourceAPIApp) addVolumeRequestHandler(request *restful.Request, - opts.VolumeSource.DataVolume.Hotpluggable = true - } else if opts.VolumeSource.PersistentVolumeClaim != nil { - opts.VolumeSource.PersistentVolumeClaim.Hotpluggable = true -+ } else if opts.VolumeSource.ContainerDisk != nil { -+ opts.VolumeSource.ContainerDisk.Hotpluggable = true - } - - // inject into VMI if ephemeral, else set as a request on the VM to both make permanent and hotplug. -diff --git a/pkg/virt-api/webhooks/validating-webhook/admitters/vmi-update-admitter.go b/pkg/virt-api/webhooks/validating-webhook/admitters/vmi-update-admitter.go -index 0af25f8074..b984ff4262 100644 ---- a/pkg/virt-api/webhooks/validating-webhook/admitters/vmi-update-admitter.go -+++ b/pkg/virt-api/webhooks/validating-webhook/admitters/vmi-update-admitter.go -@@ -200,11 +200,11 @@ func verifyHotplugVolumes(newHotplugVolumeMap, oldHotplugVolumeMap map[string]v1 - } - } else { - // This is a new volume, ensure that the volume is either DV, PVC or memoryDumpVolume -- if v.DataVolume == nil && v.PersistentVolumeClaim == nil && v.MemoryDump == nil { -+ if v.DataVolume == nil && v.PersistentVolumeClaim == nil && v.MemoryDump == nil && v.ContainerDisk == nil { - return webhookutils.ToAdmissionResponse([]metav1.StatusCause{ - { - Type: metav1.CauseTypeFieldValueInvalid, -- Message: fmt.Sprintf("volume %s is not a PVC or DataVolume", k), -+ Message: fmt.Sprintf("volume %s is not a PVC,DataVolume,MemoryDumpVolume or ContainerDisk", k), - }, - }) - } -@@ -219,19 +219,19 @@ func verifyHotplugVolumes(newHotplugVolumeMap, oldHotplugVolumeMap map[string]v1 - }) - } - disk := newDisks[k] -- if disk.Disk == nil && disk.LUN == nil { -+ if disk.Disk == nil && disk.LUN == nil && disk.CDRom == nil { - return webhookutils.ToAdmissionResponse([]metav1.StatusCause{ - { - Type: metav1.CauseTypeFieldValueInvalid, -- Message: fmt.Sprintf("Disk %s requires diskDevice of type 'disk' or 'lun' to be hotplugged.", k), -+ Message: fmt.Sprintf("Disk %s requires diskDevice of type 'disk','lun' or cdrom to be hotplugged.", k), - }, - }) - } -- if (disk.Disk == nil || disk.Disk.Bus != "scsi") && (disk.LUN == nil || disk.LUN.Bus != "scsi") { -+ if (disk.Disk != nil && disk.Disk.Bus != v1.DiskBusSCSI) || (disk.LUN != nil && disk.LUN.Bus != v1.DiskBusSCSI) || (disk.CDRom != nil && disk.CDRom.Bus != v1.DiskBusSCSI) { - return webhookutils.ToAdmissionResponse([]metav1.StatusCause{ - { - Type: metav1.CauseTypeFieldValueInvalid, -- Message: fmt.Sprintf("hotplugged Disk %s does not use a scsi bus", k), -+ Message: fmt.Sprintf("hotplugged Disk %s does not use a %q bus", k, v1.DiskBusSCSI), - }, - }) - -diff --git a/pkg/virt-api/webhooks/validating-webhook/admitters/vms-admitter.go b/pkg/virt-api/webhooks/validating-webhook/admitters/vms-admitter.go -index f7e4f92727..edaf475e05 100644 ---- a/pkg/virt-api/webhooks/validating-webhook/admitters/vms-admitter.go -+++ b/pkg/virt-api/webhooks/validating-webhook/admitters/vms-admitter.go -@@ -591,6 +591,8 @@ func (admitter *VMsAdmitter) validateVolumeRequests(vm *v1.VirtualMachine) ([]me - newVolume.VolumeSource.PersistentVolumeClaim = volumeRequest.AddVolumeOptions.VolumeSource.PersistentVolumeClaim - } else if volumeRequest.AddVolumeOptions.VolumeSource.DataVolume != nil { - newVolume.VolumeSource.DataVolume = volumeRequest.AddVolumeOptions.VolumeSource.DataVolume -+ } else if volumeRequest.AddVolumeOptions.VolumeSource.ContainerDisk != nil { -+ newVolume.VolumeSource.ContainerDisk = volumeRequest.AddVolumeOptions.VolumeSource.ContainerDisk - } - - vmVolume, ok := vmVolumeMap[name] -@@ -666,7 +668,6 @@ func (admitter *VMsAdmitter) validateVolumeRequests(vm *v1.VirtualMachine) ([]me - } - - func validateDiskConfiguration(disk *v1.Disk, name string) []metav1.StatusCause { -- var bus v1.DiskBus - // Validate the disk is configured properly - if disk == nil { - return []metav1.StatusCause{{ -@@ -675,19 +676,23 @@ func validateDiskConfiguration(disk *v1.Disk, name string) []metav1.StatusCause - Field: k8sfield.NewPath("Status", "volumeRequests").String(), - }} - } -- if disk.DiskDevice.Disk == nil && disk.DiskDevice.LUN == nil { -+ var bus v1.DiskBus -+ switch { -+ case disk.DiskDevice.Disk != nil: -+ bus = disk.DiskDevice.Disk.Bus -+ case disk.DiskDevice.LUN != nil: -+ bus = disk.DiskDevice.LUN.Bus -+ case disk.DiskDevice.CDRom != nil: -+ bus = disk.DiskDevice.CDRom.Bus -+ default: - return []metav1.StatusCause{{ - Type: metav1.CauseTypeFieldValueInvalid, -- Message: fmt.Sprintf("AddVolume request for [%s] requires diskDevice of type 'disk' or 'lun' to be used.", name), -+ Message: fmt.Sprintf("AddVolume request for [%s] requires diskDevice of type 'disk',lun' or 'cdrom' to be used.", name), - Field: k8sfield.NewPath("Status", "volumeRequests").String(), - }} - } -- if disk.DiskDevice.Disk != nil { -- bus = disk.DiskDevice.Disk.Bus -- } else { -- bus = disk.DiskDevice.LUN.Bus -- } -- if bus != "scsi" { -+ -+ if bus != v1.DiskBusSCSI { - return []metav1.StatusCause{{ - Type: metav1.CauseTypeFieldValueInvalid, - Message: fmt.Sprintf("AddVolume request for [%s] requires disk bus to be 'scsi'. [%s] is not permitted", name, bus), -diff --git a/pkg/virt-controller/services/rendervolumes.go b/pkg/virt-controller/services/rendervolumes.go -index 0181fc05e3..de90ed3cbc 100644 ---- a/pkg/virt-controller/services/rendervolumes.go -+++ b/pkg/virt-controller/services/rendervolumes.go -@@ -296,7 +296,9 @@ func hotplugVolumes(vmiVolumeStatus []v1.VolumeStatus, vmiSpecVolumes []v1.Volum - } - // This detects hotplug volumes for a started but not ready VMI - for _, volume := range vmiSpecVolumes { -- if (volume.DataVolume != nil && volume.DataVolume.Hotpluggable) || (volume.PersistentVolumeClaim != nil && volume.PersistentVolumeClaim.Hotpluggable) { -+ if (volume.DataVolume != nil && volume.DataVolume.Hotpluggable) || -+ (volume.PersistentVolumeClaim != nil && volume.PersistentVolumeClaim.Hotpluggable) || -+ (volume.ContainerDisk != nil && volume.ContainerDisk.Hotpluggable) { - hotplugVolumeSet[volume.Name] = struct{}{} - } - } -diff --git a/pkg/virt-controller/services/template.go b/pkg/virt-controller/services/template.go -index 76ed7307ec..f607c24786 100644 ---- a/pkg/virt-controller/services/template.go -+++ b/pkg/virt-controller/services/template.go -@@ -64,13 +64,15 @@ import ( - ) - - const ( -- containerDisks = "container-disks" -- hotplugDisks = "hotplug-disks" -- hookSidecarSocks = "hook-sidecar-sockets" -- varRun = "/var/run" -- virtBinDir = "virt-bin-share-dir" -- hotplugDisk = "hotplug-disk" -- virtExporter = "virt-exporter" -+ containerDisks = "container-disks" -+ hotplugDisks = "hotplug-disks" -+ hookSidecarSocks = "hook-sidecar-sockets" -+ varRun = "/var/run" -+ virtBinDir = "virt-bin-share-dir" -+ hotplugDisk = "hotplug-disk" -+ virtExporter = "virt-exporter" -+ hotplugContainerDisks = "hotplug-container-disks" -+ HotplugContainerDisk = "hotplug-container-disk-" - ) - - const KvmDevice = "devices.virtualization.deckhouse.io/kvm" -@@ -846,6 +848,49 @@ func sidecarContainerName(i int) string { - return fmt.Sprintf("hook-sidecar-%d", i) - } - -+func sidecarContainerHotplugContainerdDiskName(name string) string { -+ return fmt.Sprintf("%s%s", HotplugContainerDisk, name) -+} -+ -+func (t *templateService) containerForHotplugContainerDisk(name string, cd *v1.ContainerDiskSource, vmi *v1.VirtualMachineInstance) k8sv1.Container { -+ runUser := int64(util.NonRootUID) -+ sharedMount := k8sv1.MountPropagationHostToContainer -+ path := fmt.Sprintf("/path/%s", name) -+ command := []string{"/init/usr/bin/container-disk"} -+ args := []string{"--copy-path", path} -+ -+ return k8sv1.Container{ -+ Name: name, -+ Image: cd.Image, -+ Command: command, -+ Args: args, -+ Resources: hotplugContainerResourceRequirementsForVMI(vmi, t.clusterConfig), -+ SecurityContext: &k8sv1.SecurityContext{ -+ AllowPrivilegeEscalation: pointer.Bool(false), -+ RunAsNonRoot: pointer.Bool(true), -+ RunAsUser: &runUser, -+ SeccompProfile: &k8sv1.SeccompProfile{ -+ Type: k8sv1.SeccompProfileTypeRuntimeDefault, -+ }, -+ Capabilities: &k8sv1.Capabilities{ -+ Drop: []k8sv1.Capability{"ALL"}, -+ }, -+ SELinuxOptions: &k8sv1.SELinuxOptions{ -+ Type: t.clusterConfig.GetSELinuxLauncherType(), -+ Level: "s0", -+ }, -+ }, -+ VolumeMounts: []k8sv1.VolumeMount{ -+ initContainerVolumeMount(), -+ { -+ Name: hotplugContainerDisks, -+ MountPath: "/path", -+ MountPropagation: &sharedMount, -+ }, -+ }, -+ } -+} -+ - func (t *templateService) RenderHotplugAttachmentPodTemplate(volumes []*v1.Volume, ownerPod *k8sv1.Pod, vmi *v1.VirtualMachineInstance, claimMap map[string]*k8sv1.PersistentVolumeClaim) (*k8sv1.Pod, error) { - zero := int64(0) - runUser := int64(util.NonRootUID) -@@ -924,6 +969,30 @@ func (t *templateService) RenderHotplugAttachmentPodTemplate(volumes []*v1.Volum - TerminationGracePeriodSeconds: &zero, - }, - } -+ first := true -+ for _, vol := range vmi.Spec.Volumes { -+ if vol.ContainerDisk == nil || !vol.ContainerDisk.Hotpluggable { -+ continue -+ } -+ name := sidecarContainerHotplugContainerdDiskName(vol.Name) -+ pod.Spec.Containers = append(pod.Spec.Containers, t.containerForHotplugContainerDisk(name, vol.ContainerDisk, vmi)) -+ if first { -+ first = false -+ userId := int64(util.NonRootUID) -+ initContainerCommand := []string{"/usr/bin/cp", -+ "/usr/bin/container-disk", -+ "/init/usr/bin/container-disk", -+ } -+ pod.Spec.InitContainers = append( -+ pod.Spec.InitContainers, -+ t.newInitContainerRenderer(vmi, -+ initContainerVolumeMount(), -+ initContainerResourceRequirementsForVMI(vmi, v1.ContainerDisk, t.clusterConfig), -+ userId).Render(initContainerCommand)) -+ pod.Spec.Volumes = append(pod.Spec.Volumes, emptyDirVolume(hotplugContainerDisks)) -+ pod.Spec.Volumes = append(pod.Spec.Volumes, emptyDirVolume(virtBinDir)) -+ } -+ } - - err := matchSELinuxLevelOfVMI(pod, vmi) - if err != nil { -diff --git a/pkg/virt-controller/watch/BUILD.bazel b/pkg/virt-controller/watch/BUILD.bazel -index 4fd325ba86..82fcaee0a3 100644 ---- a/pkg/virt-controller/watch/BUILD.bazel -+++ b/pkg/virt-controller/watch/BUILD.bazel -@@ -101,6 +101,7 @@ go_library( - "//vendor/k8s.io/client-go/util/flowcontrol:go_default_library", - "//vendor/k8s.io/client-go/util/workqueue:go_default_library", - "//vendor/k8s.io/utils/pointer:go_default_library", -+ "//vendor/k8s.io/utils/ptr:go_default_library", - "//vendor/k8s.io/utils/trace:go_default_library", - "//vendor/kubevirt.io/containerized-data-importer-api/pkg/apis/core/v1beta1:go_default_library", - ], -diff --git a/pkg/virt-controller/watch/vmi.go b/pkg/virt-controller/watch/vmi.go -index fa4e86ee17..c40f1fad89 100644 ---- a/pkg/virt-controller/watch/vmi.go -+++ b/pkg/virt-controller/watch/vmi.go -@@ -32,6 +32,7 @@ import ( - - "k8s.io/utils/ptr" - -+ container_disk "kubevirt.io/kubevirt/pkg/container-disk" - "kubevirt.io/kubevirt/pkg/virt-controller/network" - - "kubevirt.io/kubevirt/pkg/virt-controller/watch/topology" -@@ -1774,12 +1775,18 @@ func (c *VMIController) needsHandleHotplug(hotplugVolumes []*virtv1.Volume, hotp - } - - func (c *VMIController) getActiveAndOldAttachmentPods(readyHotplugVolumes []*virtv1.Volume, hotplugAttachmentPods []*k8sv1.Pod) (*k8sv1.Pod, []*k8sv1.Pod) { -+ sort.Slice(hotplugAttachmentPods, func(i, j int) bool { -+ return hotplugAttachmentPods[i].CreationTimestamp.Time.Before(hotplugAttachmentPods[j].CreationTimestamp.Time) -+ }) - var currentPod *k8sv1.Pod - oldPods := make([]*k8sv1.Pod, 0) - for _, attachmentPod := range hotplugAttachmentPods { - if !c.podVolumesMatchesReadyVolumes(attachmentPod, readyHotplugVolumes) { - oldPods = append(oldPods, attachmentPod) - } else { -+ if currentPod != nil { -+ oldPods = append(oldPods, currentPod) -+ } - currentPod = attachmentPod - } - } -@@ -1836,6 +1843,10 @@ func (c *VMIController) handleHotplugVolumes(hotplugVolumes []*virtv1.Volume, ho - readyHotplugVolumes := make([]*virtv1.Volume, 0) - // Find all ready volumes - for _, volume := range hotplugVolumes { -+ if container_disk.IsHotplugContainerDisk(volume) { -+ readyHotplugVolumes = append(readyHotplugVolumes, volume) -+ continue -+ } - var err error - ready, wffc, err := storagetypes.VolumeReadyToAttachToNode(vmi.Namespace, *volume, dataVolumes, c.dataVolumeIndexer, c.pvcIndexer) - if err != nil { -@@ -1883,20 +1894,45 @@ func (c *VMIController) handleHotplugVolumes(hotplugVolumes []*virtv1.Volume, ho - } - - func (c *VMIController) podVolumesMatchesReadyVolumes(attachmentPod *k8sv1.Pod, volumes []*virtv1.Volume) bool { -- // -2 for empty dir and token -- if len(attachmentPod.Spec.Volumes)-2 != len(volumes) { -+ const ( -+ // -2 for empty dir and token -+ subVols = 2 -+ // -4 for hotplug with ContainerDisk. 3 empty dir + token -+ subVolsWithContainerDisk = 4 -+ ) -+ containerDisksNames := make(map[string]struct{}) -+ for _, ctr := range attachmentPod.Spec.Containers { -+ if strings.HasPrefix(ctr.Name, services.HotplugContainerDisk) { -+ containerDisksNames[strings.TrimPrefix(ctr.Name, services.HotplugContainerDisk)] = struct{}{} -+ } -+ } -+ -+ var sub = subVols -+ if len(containerDisksNames) > 0 { -+ sub = subVolsWithContainerDisk -+ } -+ -+ countAttachmentVolumes := len(attachmentPod.Spec.Volumes) - sub + len(containerDisksNames) -+ -+ if countAttachmentVolumes != len(volumes) { - return false - } -- podVolumeMap := make(map[string]k8sv1.Volume) -+ -+ podVolumeMap := make(map[string]struct{}) - for _, volume := range attachmentPod.Spec.Volumes { - if volume.PersistentVolumeClaim != nil { -- podVolumeMap[volume.Name] = volume -+ podVolumeMap[volume.Name] = struct{}{} - } - } -+ - for _, volume := range volumes { -+ if container_disk.IsHotplugContainerDisk(volume) { -+ delete(containerDisksNames, volume.Name) -+ continue -+ } - delete(podVolumeMap, volume.Name) - } -- return len(podVolumeMap) == 0 -+ return len(podVolumeMap) == 0 && len(containerDisksNames) == 0 - } - - func (c *VMIController) createAttachmentPod(vmi *virtv1.VirtualMachineInstance, virtLauncherPod *k8sv1.Pod, volumes []*virtv1.Volume) (*k8sv1.Pod, syncError) { -@@ -2007,7 +2043,17 @@ func (c *VMIController) createAttachmentPodTemplate(vmi *virtv1.VirtualMachineIn - var pod *k8sv1.Pod - var err error - -- volumeNamesPVCMap, err := storagetypes.VirtVolumesToPVCMap(volumes, c.pvcIndexer, virtlauncherPod.Namespace) -+ var hasContainerDisk bool -+ var newVolumes []*virtv1.Volume -+ for _, volume := range volumes { -+ if volume.VolumeSource.ContainerDisk != nil { -+ hasContainerDisk = true -+ continue -+ } -+ newVolumes = append(newVolumes, volume) -+ } -+ -+ volumeNamesPVCMap, err := storagetypes.VirtVolumesToPVCMap(newVolumes, c.pvcIndexer, virtlauncherPod.Namespace) - if err != nil { - return nil, fmt.Errorf("failed to get PVC map: %v", err) - } -@@ -2029,7 +2075,7 @@ func (c *VMIController) createAttachmentPodTemplate(vmi *virtv1.VirtualMachineIn - } - } - -- if len(volumeNamesPVCMap) > 0 { -+ if len(volumeNamesPVCMap) > 0 || hasContainerDisk { - pod, err = c.templateService.RenderHotplugAttachmentPodTemplate(volumes, virtlauncherPod, vmi, volumeNamesPVCMap) - } - return pod, err -@@ -2151,23 +2197,68 @@ func (c *VMIController) updateVolumeStatus(vmi *virtv1.VirtualMachineInstance, v - ClaimName: volume.Name, - } - } -+ if volume.ContainerDisk != nil && status.ContainerDiskVolume == nil { -+ status.ContainerDiskVolume = &virtv1.ContainerDiskInfo{} -+ } - if attachmentPod == nil { -- if !c.volumeReady(status.Phase) { -+ if volume.ContainerDisk != nil { - status.HotplugVolume.AttachPodUID = "" -- // Volume is not hotplugged in VM and Pod is gone, or hasn't been created yet, check for the PVC associated with the volume to set phase and message -- phase, reason, message := c.getVolumePhaseMessageReason(&vmi.Spec.Volumes[i], vmi.Namespace) -- status.Phase = phase -- status.Message = message -- status.Reason = reason -+ status.Phase = virtv1.VolumePending -+ status.Message = "Attachment pod not found" -+ status.Reason = "AttachmentPodNotFound" -+ } else { -+ if !c.volumeReady(status.Phase) { -+ status.HotplugVolume.AttachPodUID = "" -+ // Volume is not hotplugged in VM and Pod is gone, or hasn't been created yet, check for the PVC associated with the volume to set phase and message -+ phase, reason, message := c.getVolumePhaseMessageReason(&vmi.Spec.Volumes[i], vmi.Namespace) -+ status.Phase = phase -+ status.Message = message -+ status.Reason = reason -+ } - } - } else { - status.HotplugVolume.AttachPodName = attachmentPod.Name -- if len(attachmentPod.Status.ContainerStatuses) == 1 && attachmentPod.Status.ContainerStatuses[0].Ready { -+ if volume.ContainerDisk != nil { -+ var ( -+ uid types.UID -+ isReady bool -+ ) -+ for _, cs := range attachmentPod.Status.ContainerStatuses { -+ name := strings.TrimPrefix(cs.Name, "hotplug-container-disk-") -+ if volume.Name == name { -+ uid = attachmentPod.UID -+ isReady = cs.Ready -+ break -+ } -+ } -+ if isReady { -+ status.HotplugVolume.AttachPodUID = uid -+ } else { -+ status.HotplugVolume.AttachPodUID = "" -+ -+ } -+ } else if len(attachmentPod.Status.ContainerStatuses) == 1 && attachmentPod.Status.ContainerStatuses[0].Ready { - status.HotplugVolume.AttachPodUID = attachmentPod.UID -+ } else if volume.PersistentVolumeClaim != nil { -+ var isReady bool -+ for _, cs := range attachmentPod.Status.ContainerStatuses { -+ if cs.Name == "hotplug-disk" { -+ isReady = cs.Ready -+ break -+ } -+ } -+ -+ if isReady { -+ status.HotplugVolume.AttachPodUID = attachmentPod.UID -+ } else { -+ // Remove UID of old pod if a new one is available, but not yet ready -+ status.HotplugVolume.AttachPodUID = "" -+ } - } else { - // Remove UID of old pod if a new one is available, but not yet ready - status.HotplugVolume.AttachPodUID = "" - } -+ - if c.canMoveToAttachedPhase(status.Phase) { - status.Phase = virtv1.HotplugVolumeAttachedToNode - status.Message = fmt.Sprintf("Created hotplug attachment pod %s, for volume %s", attachmentPod.Name, volume.Name) -@@ -2176,7 +2267,6 @@ func (c *VMIController) updateVolumeStatus(vmi *virtv1.VirtualMachineInstance, v - } - } - } -- - if volume.VolumeSource.PersistentVolumeClaim != nil || volume.VolumeSource.DataVolume != nil || volume.VolumeSource.MemoryDump != nil { - - pvcName := storagetypes.PVCNameFromVirtVolume(&volume) -diff --git a/pkg/virt-handler/container-disk/hotplug.go b/pkg/virt-handler/container-disk/hotplug.go -new file mode 100644 -index 0000000000..993d1be31b ---- /dev/null -+++ b/pkg/virt-handler/container-disk/hotplug.go -@@ -0,0 +1,676 @@ -+package container_disk -+ -+import ( -+ "encoding/json" -+ "errors" -+ "fmt" -+ "os" -+ "path/filepath" -+ "strings" -+ "sync" -+ "time" -+ -+ hotplugdisk "kubevirt.io/kubevirt/pkg/hotplug-disk" -+ "kubevirt.io/kubevirt/pkg/unsafepath" -+ -+ "kubevirt.io/kubevirt/pkg/safepath" -+ virtconfig "kubevirt.io/kubevirt/pkg/virt-config" -+ virt_chroot "kubevirt.io/kubevirt/pkg/virt-handler/virt-chroot" -+ -+ "kubevirt.io/client-go/log" -+ -+ containerdisk "kubevirt.io/kubevirt/pkg/container-disk" -+ diskutils "kubevirt.io/kubevirt/pkg/ephemeral-disk-utils" -+ "kubevirt.io/kubevirt/pkg/virt-handler/isolation" -+ -+ "k8s.io/apimachinery/pkg/api/equality" -+ "k8s.io/apimachinery/pkg/types" -+ -+ v1 "kubevirt.io/api/core/v1" -+) -+ -+type HotplugMounter interface { -+ ContainerDisksReady(vmi *v1.VirtualMachineInstance, notInitializedSince time.Time, sourceUID types.UID) (bool, error) -+ MountAndVerify(vmi *v1.VirtualMachineInstance) (map[string]*containerdisk.DiskInfo, error) -+ MoundAndVerifyFromPod(vmi *v1.VirtualMachineInstance, sourceUID types.UID) (map[string]*containerdisk.DiskInfo, error) -+ IsMounted(vmi *v1.VirtualMachineInstance, volumeName string) (bool, error) -+ Umount(vmi *v1.VirtualMachineInstance) error -+ UmountAll(vmi *v1.VirtualMachineInstance) error -+ ComputeChecksums(vmi *v1.VirtualMachineInstance, sourceUID types.UID) (*DiskChecksums, error) -+} -+ -+type hotplugMounter struct { -+ podIsolationDetector isolation.PodIsolationDetector -+ mountStateDir string -+ mountRecords map[types.UID]*vmiMountTargetRecord -+ mountRecordsLock sync.Mutex -+ suppressWarningTimeout time.Duration -+ clusterConfig *virtconfig.ClusterConfig -+ nodeIsolationResult isolation.IsolationResult -+ -+ hotplugPathGetter containerdisk.HotplugSocketPathGetter -+ hotplugManager hotplugdisk.HotplugDiskManagerInterface -+} -+ -+func (m *hotplugMounter) IsMounted(vmi *v1.VirtualMachineInstance, volumeName string) (bool, error) { -+ virtLauncherUID := m.findVirtlauncherUID(vmi) -+ if virtLauncherUID == "" { -+ return false, nil -+ } -+ target, err := m.hotplugManager.GetFileSystemDiskTargetPathFromHostView(virtLauncherUID, volumeName, false) -+ if err != nil { -+ return false, err -+ } -+ return isolation.IsMounted(target) -+} -+ -+func NewHotplugMounter(isoDetector isolation.PodIsolationDetector, -+ mountStateDir string, -+ clusterConfig *virtconfig.ClusterConfig, -+ hotplugManager hotplugdisk.HotplugDiskManagerInterface, -+) HotplugMounter { -+ return &hotplugMounter{ -+ mountRecords: make(map[types.UID]*vmiMountTargetRecord), -+ podIsolationDetector: isoDetector, -+ mountStateDir: mountStateDir, -+ suppressWarningTimeout: 1 * time.Minute, -+ clusterConfig: clusterConfig, -+ nodeIsolationResult: isolation.NodeIsolationResult(), -+ -+ hotplugPathGetter: containerdisk.NewHotplugSocketPathGetter(""), -+ hotplugManager: hotplugManager, -+ } -+} -+ -+func (m *hotplugMounter) deleteMountTargetRecord(vmi *v1.VirtualMachineInstance) error { -+ if string(vmi.UID) == "" { -+ return fmt.Errorf("unable to find container disk mounted directories for vmi without uid") -+ } -+ -+ recordFile := filepath.Join(m.mountStateDir, string(vmi.UID)) -+ -+ exists, err := diskutils.FileExists(recordFile) -+ if err != nil { -+ return err -+ } -+ -+ if exists { -+ record, err := m.getMountTargetRecord(vmi) -+ if err != nil { -+ return err -+ } -+ -+ for _, target := range record.MountTargetEntries { -+ os.Remove(target.TargetFile) -+ os.Remove(target.SocketFile) -+ } -+ -+ os.Remove(recordFile) -+ } -+ -+ m.mountRecordsLock.Lock() -+ defer m.mountRecordsLock.Unlock() -+ delete(m.mountRecords, vmi.UID) -+ -+ return nil -+} -+ -+func (m *hotplugMounter) getMountTargetRecord(vmi *v1.VirtualMachineInstance) (*vmiMountTargetRecord, error) { -+ var ok bool -+ var existingRecord *vmiMountTargetRecord -+ -+ if string(vmi.UID) == "" { -+ return nil, fmt.Errorf("unable to find container disk mounted directories for vmi without uid") -+ } -+ -+ m.mountRecordsLock.Lock() -+ defer m.mountRecordsLock.Unlock() -+ existingRecord, ok = m.mountRecords[vmi.UID] -+ -+ // first check memory cache -+ if ok { -+ return existingRecord, nil -+ } -+ -+ // if not there, see if record is on disk, this can happen if virt-handler restarts -+ recordFile := filepath.Join(m.mountStateDir, filepath.Clean(string(vmi.UID))) -+ -+ exists, err := diskutils.FileExists(recordFile) -+ if err != nil { -+ return nil, err -+ } -+ -+ if exists { -+ record := vmiMountTargetRecord{} -+ // #nosec No risk for path injection. Using static base and cleaned filename -+ bytes, err := os.ReadFile(recordFile) -+ if err != nil { -+ return nil, err -+ } -+ err = json.Unmarshal(bytes, &record) -+ if err != nil { -+ return nil, err -+ } -+ -+ if !record.UsesSafePaths { -+ record.UsesSafePaths = true -+ for i, entry := range record.MountTargetEntries { -+ safePath, err := safepath.JoinAndResolveWithRelativeRoot("/", entry.TargetFile) -+ if err != nil { -+ return nil, fmt.Errorf("failed converting legacy path to safepath: %v", err) -+ } -+ record.MountTargetEntries[i].TargetFile = unsafepath.UnsafeAbsolute(safePath.Raw()) -+ } -+ } -+ -+ m.mountRecords[vmi.UID] = &record -+ return &record, nil -+ } -+ -+ // not found -+ return nil, nil -+} -+ -+func (m *hotplugMounter) addMountTargetRecord(vmi *v1.VirtualMachineInstance, record *vmiMountTargetRecord) error { -+ return m.setAddMountTargetRecordHelper(vmi, record, true) -+} -+ -+func (m *hotplugMounter) setMountTargetRecord(vmi *v1.VirtualMachineInstance, record *vmiMountTargetRecord) error { -+ return m.setAddMountTargetRecordHelper(vmi, record, false) -+} -+ -+func (m *hotplugMounter) setAddMountTargetRecordHelper(vmi *v1.VirtualMachineInstance, record *vmiMountTargetRecord, addPreviousRules bool) error { -+ if string(vmi.UID) == "" { -+ return fmt.Errorf("unable to set container disk mounted directories for vmi without uid") -+ } -+ -+ record.UsesSafePaths = true -+ -+ recordFile := filepath.Join(m.mountStateDir, string(vmi.UID)) -+ fileExists, err := diskutils.FileExists(recordFile) -+ if err != nil { -+ return err -+ } -+ -+ m.mountRecordsLock.Lock() -+ defer m.mountRecordsLock.Unlock() -+ -+ existingRecord, ok := m.mountRecords[vmi.UID] -+ if ok && fileExists && equality.Semantic.DeepEqual(existingRecord, record) { -+ // already done -+ return nil -+ } -+ -+ if addPreviousRules && existingRecord != nil && len(existingRecord.MountTargetEntries) > 0 { -+ record.MountTargetEntries = append(record.MountTargetEntries, existingRecord.MountTargetEntries...) -+ } -+ -+ bytes, err := json.Marshal(record) -+ if err != nil { -+ return err -+ } -+ -+ err = os.MkdirAll(filepath.Dir(recordFile), 0750) -+ if err != nil { -+ return err -+ } -+ -+ err = os.WriteFile(recordFile, bytes, 0600) -+ if err != nil { -+ return err -+ } -+ -+ m.mountRecords[vmi.UID] = record -+ -+ return nil -+} -+ -+func (m *hotplugMounter) MoundAndVerifyFromPod(vmi *v1.VirtualMachineInstance, sourceUID types.UID) (map[string]*containerdisk.DiskInfo, error) { -+ return m.mountAndVerify(vmi, sourceUID) -+} -+ -+func (m *hotplugMounter) MountAndVerify(vmi *v1.VirtualMachineInstance) (map[string]*containerdisk.DiskInfo, error) { -+ return m.mountAndVerify(vmi, "") -+} -+ -+func (m *hotplugMounter) mountAndVerify(vmi *v1.VirtualMachineInstance, sourceUID types.UID) (map[string]*containerdisk.DiskInfo, error) { -+ virtLauncherUID := m.findVirtlauncherUID(vmi) -+ if virtLauncherUID == "" { -+ return nil, nil -+ } -+ -+ record := vmiMountTargetRecord{} -+ disksInfo := map[string]*containerdisk.DiskInfo{} -+ -+ for _, volume := range vmi.Spec.Volumes { -+ if volume.ContainerDisk != nil && volume.ContainerDisk.Hotpluggable { -+ entry, err := m.newMountTargetEntry(vmi, virtLauncherUID, sourceUID, volume.Name) -+ if err != nil { -+ return nil, err -+ } -+ record.MountTargetEntries = append(record.MountTargetEntries, entry) -+ } -+ } -+ -+ if len(record.MountTargetEntries) > 0 { -+ err := m.setMountTargetRecord(vmi, &record) -+ if err != nil { -+ return nil, err -+ } -+ } -+ -+ vmiRes, err := m.podIsolationDetector.Detect(vmi) -+ if err != nil { -+ return nil, fmt.Errorf("failed to detect VMI pod: %v", err) -+ } -+ -+ for _, volume := range vmi.Spec.Volumes { -+ if volume.ContainerDisk != nil && volume.ContainerDisk.Hotpluggable { -+ target, err := m.hotplugManager.GetFileSystemDiskTargetPathFromHostView(virtLauncherUID, volume.Name, false) -+ -+ if isMounted, err := isolation.IsMounted(target); err != nil { -+ return nil, fmt.Errorf("failed to determine if %s is already mounted: %v", target, err) -+ } else if !isMounted { -+ -+ sourceFile, err := m.getContainerDiskPath(vmi, &volume, volume.Name, sourceUID) -+ if err != nil { -+ return nil, fmt.Errorf("failed to find a sourceFile in containerDisk %v: %v", volume.Name, err) -+ } -+ -+ log.DefaultLogger().Object(vmi).Infof("Bind mounting container disk at %s to %s", sourceFile, target) -+ opts := []string{ -+ "bind", "ro", "uid=107", "gid=107", -+ } -+ err = virt_chroot.MountChrootWithOptions(sourceFile, target, opts...) -+ if err != nil { -+ return nil, fmt.Errorf("failed to bindmount containerDisk %v. err: %w", volume.Name, err) -+ } -+ } -+ -+ imageInfo, err := isolation.GetImageInfo( -+ containerdisk.GetHotplugContainerDiskTargetPathFromLauncherView(volume.Name), -+ vmiRes, -+ m.clusterConfig.GetDiskVerification(), -+ ) -+ if err != nil { -+ return nil, fmt.Errorf("failed to get image info: %v", err) -+ } -+ if err := containerdisk.VerifyImage(imageInfo); err != nil { -+ return nil, fmt.Errorf("invalid image in containerDisk %v: %v", volume.Name, err) -+ } -+ disksInfo[volume.Name] = imageInfo -+ } -+ } -+ -+ return disksInfo, nil -+} -+ -+func (m *hotplugMounter) newMountTargetEntry( -+ vmi *v1.VirtualMachineInstance, -+ virtLauncherUID, sourceUID types.UID, -+ volumeName string, -+) (vmiMountTargetEntry, error) { -+ targetFile, err := m.getTarget(virtLauncherUID, volumeName) -+ if err != nil { -+ return vmiMountTargetEntry{}, err -+ } -+ -+ sock, err := m.hotplugPathGetter(vmi, volumeName, sourceUID) -+ if err != nil { -+ return vmiMountTargetEntry{}, err -+ } -+ return vmiMountTargetEntry{ -+ TargetFile: targetFile, -+ SocketFile: sock, -+ }, nil -+} -+ -+func (m *hotplugMounter) getTarget(virtLauncherUID types.UID, volumeName string) (string, error) { -+ target, err := m.hotplugManager.GetFileSystemDiskTargetPathFromHostView(virtLauncherUID, volumeName, true) -+ if err != nil { -+ return "", err -+ } -+ return unsafepath.UnsafeAbsolute(target.Raw()), nil -+} -+ -+func (m *hotplugMounter) getMountedVolumesInWorld(vmi *v1.VirtualMachineInstance, virtLauncherUID types.UID) ([]vmiMountTargetEntry, error) { -+ if vmi == nil || virtLauncherUID == "" { -+ return nil, nil -+ } -+ path, err := m.hotplugManager.GetHotplugTargetPodPathOnHost(virtLauncherUID) -+ if err != nil { -+ if os.IsNotExist(err) { -+ return nil, nil -+ } -+ return nil, err -+ } -+ rawPath := unsafepath.UnsafeAbsolute(path.Raw()) -+ entries, err := os.ReadDir(rawPath) -+ if err != nil { -+ if os.IsNotExist(err) { -+ return nil, nil -+ } -+ return nil, err -+ } -+ var volumes []string -+ for _, entry := range entries { -+ info, err := entry.Info() -+ if err != nil { -+ return nil, err -+ } -+ if info.IsDir() { -+ continue -+ } -+ if strings.HasSuffix(entry.Name(), ".img") { -+ name := strings.TrimSuffix(entry.Name(), ".img") -+ volumes = append(volumes, name) -+ } -+ } -+ var mountedVolumes []vmiMountTargetEntry -+ for _, v := range volumes { -+ mounted, err := m.IsMounted(vmi, v) -+ if err != nil { -+ return nil, err -+ } -+ if mounted { -+ target, err := m.getTarget(virtLauncherUID, v) -+ if err != nil { -+ return nil, err -+ } -+ mountedVolumes = append(mountedVolumes, vmiMountTargetEntry{ -+ TargetFile: target, -+ }) -+ } -+ } -+ return mountedVolumes, nil -+} -+ -+func (m *hotplugMounter) mergeMountEntries(r1, r2 []vmiMountTargetEntry) []vmiMountTargetEntry { -+ targetSocket := make(map[string]string) -+ -+ sortTargetSocket := func(r []vmiMountTargetEntry) { -+ for _, entry := range r { -+ socket := targetSocket[entry.TargetFile] -+ if socket == "" { -+ targetSocket[entry.TargetFile] = entry.SocketFile -+ } -+ } -+ } -+ sortTargetSocket(r1) -+ sortTargetSocket(r2) -+ -+ newRecords := make([]vmiMountTargetEntry, len(targetSocket)) -+ count := 0 -+ for t, s := range targetSocket { -+ newRecords[count] = vmiMountTargetEntry{ -+ TargetFile: t, -+ SocketFile: s, -+ } -+ count++ -+ } -+ -+ return newRecords -+} -+ -+func (m *hotplugMounter) Umount(vmi *v1.VirtualMachineInstance) error { -+ record, err := m.getMountTargetRecord(vmi) -+ if err != nil { -+ return err -+ } -+ -+ worldEntries, err := m.getMountedVolumesInWorld(vmi, m.findVirtlauncherUID(vmi)) -+ if err != nil { -+ return fmt.Errorf("failed to get world entries: %w", err) -+ } -+ var recordMountTargetEntries []vmiMountTargetEntry -+ if record != nil { -+ recordMountTargetEntries = record.MountTargetEntries -+ } -+ -+ mountEntries := m.mergeMountEntries(recordMountTargetEntries, worldEntries) -+ -+ if len(mountEntries) == 0 { -+ log.DefaultLogger().Object(vmi).Infof("No container disk mount entries found to unmount") -+ return nil -+ } -+ -+ entriesTargetForDelete := make(map[string]struct{}) -+ -+ for _, r := range mountEntries { -+ name := extractNameFromTarget(r.TargetFile) -+ -+ needUmount := true -+ for _, v := range vmi.Status.VolumeStatus { -+ if v.Name == name { -+ needUmount = false -+ } -+ } -+ if needUmount { -+ file, err := safepath.NewFileNoFollow(r.TargetFile) -+ if err != nil { -+ if errors.Is(err, os.ErrNotExist) { -+ entriesTargetForDelete[r.TargetFile] = struct{}{} -+ continue -+ } -+ return fmt.Errorf(failedCheckMountPointFmt, r.TargetFile, err) -+ } -+ _ = file.Close() -+ mounted, err := m.IsMounted(vmi, name) -+ if err != nil { -+ return fmt.Errorf(failedCheckMountPointFmt, r.TargetFile, err) -+ } -+ if !mounted { -+ if err = safepath.UnlinkAtNoFollow(file.Path()); err != nil { -+ return fmt.Errorf("failed to delete file %s: %w", file.Path(), err) -+ } -+ entriesTargetForDelete[r.TargetFile] = struct{}{} -+ continue -+ } -+ // #nosec No risk for attacket injection. Parameters are predefined strings -+ out, err := virt_chroot.UmountChroot(file.Path()).CombinedOutput() -+ if err != nil { -+ return fmt.Errorf(failedUnmountFmt, file, string(out), err) -+ } -+ if err = safepath.UnlinkAtNoFollow(file.Path()); err != nil { -+ return fmt.Errorf("failed to delete file %s: %w", file.Path(), err) -+ } -+ entriesTargetForDelete[r.TargetFile] = struct{}{} -+ } -+ } -+ newEntries := make([]vmiMountTargetEntry, 0, len(recordMountTargetEntries)-len(entriesTargetForDelete)) -+ for _, entry := range recordMountTargetEntries { -+ if _, found := entriesTargetForDelete[entry.TargetFile]; found { -+ continue -+ } -+ newEntries = append(newEntries, entry) -+ } -+ record.MountTargetEntries = newEntries -+ return m.setMountTargetRecord(vmi, record) -+} -+ -+func extractNameFromSocket(socketFile string) (string, error) { -+ base := filepath.Base(socketFile) -+ if strings.HasPrefix(base, "hotplug-container-disk-") && strings.HasSuffix(base, ".sock") { -+ name := strings.TrimPrefix(base, "hotplug-container-disk-") -+ name = strings.TrimSuffix(name, ".sock") -+ return name, nil -+ } -+ return "", fmt.Errorf("name not found in path") -+} -+ -+func extractNameFromTarget(targetFile string) string { -+ filename := filepath.Base(targetFile) -+ name := strings.TrimSuffix(filename, filepath.Ext(filename)) -+ return name -+} -+ -+func (m *hotplugMounter) UmountAll(vmi *v1.VirtualMachineInstance) error { -+ if vmi.UID == "" { -+ return nil -+ } -+ -+ record, err := m.getMountTargetRecord(vmi) -+ if err != nil { -+ return err -+ } -+ -+ worldEntries, err := m.getMountedVolumesInWorld(vmi, m.findVirtlauncherUID(vmi)) -+ if err != nil { -+ return fmt.Errorf("failed to get world entries: %w", err) -+ } -+ var recordMountTargetEntries []vmiMountTargetEntry -+ if record != nil { -+ recordMountTargetEntries = record.MountTargetEntries -+ } -+ -+ mountEntries := m.mergeMountEntries(recordMountTargetEntries, worldEntries) -+ -+ if len(mountEntries) == 0 { -+ log.DefaultLogger().Object(vmi).Infof("No container disk mount entries found to unmount") -+ return nil -+ } -+ -+ log.DefaultLogger().Object(vmi).Infof("Found container disk mount entries") -+ -+ for _, entry := range mountEntries { -+ log.DefaultLogger().Object(vmi).Infof("Looking to see if containerdisk is mounted at path %s", entry.TargetFile) -+ file, err := safepath.NewFileNoFollow(entry.TargetFile) -+ if err != nil { -+ if errors.Is(err, os.ErrNotExist) { -+ continue -+ } -+ return fmt.Errorf(failedCheckMountPointFmt, entry.TargetFile, err) -+ } -+ _ = file.Close() -+ if mounted, err := isolation.IsMounted(file.Path()); err != nil { -+ return fmt.Errorf(failedCheckMountPointFmt, file, err) -+ } else if mounted { -+ log.DefaultLogger().Object(vmi).Infof("unmounting container disk at path %s", file) -+ // #nosec No risk for attacket injection. Parameters are predefined strings -+ out, err := virt_chroot.UmountChroot(file.Path()).CombinedOutput() -+ if err != nil { -+ return fmt.Errorf(failedUnmountFmt, file, string(out), err) -+ } -+ if err = safepath.UnlinkAtNoFollow(file.Path()); err != nil { -+ return fmt.Errorf("failed to delete file %s: %w", file.Path(), err) -+ } -+ } else { -+ if err = safepath.UnlinkAtNoFollow(file.Path()); err != nil { -+ return fmt.Errorf("failed to delete file %s: %w", file.Path(), err) -+ } -+ } -+ } -+ err = m.deleteMountTargetRecord(vmi) -+ if err != nil { -+ return err -+ } -+ -+ return nil -+} -+ -+func (m *hotplugMounter) ContainerDisksReady(vmi *v1.VirtualMachineInstance, notInitializedSince time.Time, sourceUID types.UID) (bool, error) { -+ for _, volume := range vmi.Spec.Volumes { -+ if containerdisk.IsHotplugContainerDisk(&volume) { -+ _, err := m.hotplugPathGetter(vmi, volume.Name, sourceUID) -+ if err != nil { -+ log.DefaultLogger().Object(vmi).Reason(err).Infof("hotplug containerdisk %s not yet ready", volume.Name) -+ if time.Now().After(notInitializedSince.Add(m.suppressWarningTimeout)) { -+ return false, fmt.Errorf("hotplug containerdisk %s still not ready after one minute", volume.Name) -+ } -+ return false, nil -+ } -+ } -+ } -+ -+ log.DefaultLogger().Object(vmi).V(4).Info("all hotplug containerdisks are ready") -+ return true, nil -+} -+ -+func (m *hotplugMounter) getContainerDiskPath(vmi *v1.VirtualMachineInstance, volume *v1.Volume, volumeName string, sourceUID types.UID) (*safepath.Path, error) { -+ sock, err := m.hotplugPathGetter(vmi, volumeName, sourceUID) -+ if err != nil { -+ return nil, ErrDiskContainerGone -+ } -+ -+ res, err := m.podIsolationDetector.DetectForSocket(vmi, sock) -+ if err != nil { -+ return nil, fmt.Errorf("failed to detect socket for containerDisk %v: %v", volume.Name, err) -+ } -+ -+ mountPoint, err := isolation.ParentPathForRootMount(m.nodeIsolationResult, res) -+ if err != nil { -+ return nil, fmt.Errorf("failed to detect root mount point of containerDisk %v on the node: %v", volume.Name, err) -+ } -+ -+ return containerdisk.GetImage(mountPoint, volume.ContainerDisk.Path) -+} -+ -+func (m *hotplugMounter) ComputeChecksums(vmi *v1.VirtualMachineInstance, sourceUID types.UID) (*DiskChecksums, error) { -+ -+ diskChecksums := &DiskChecksums{ -+ ContainerDiskChecksums: map[string]uint32{}, -+ } -+ -+ for _, volume := range vmi.Spec.Volumes { -+ if volume.VolumeSource.ContainerDisk == nil || !volume.VolumeSource.ContainerDisk.Hotpluggable { -+ continue -+ } -+ -+ path, err := m.getContainerDiskPath(vmi, &volume, volume.Name, sourceUID) -+ if err != nil { -+ return nil, err -+ } -+ -+ checksum, err := getDigest(path) -+ if err != nil { -+ return nil, err -+ } -+ -+ diskChecksums.ContainerDiskChecksums[volume.Name] = checksum -+ } -+ -+ return diskChecksums, nil -+} -+ -+func (m *hotplugMounter) findVirtlauncherUID(vmi *v1.VirtualMachineInstance) (uid types.UID) { -+ cnt := 0 -+ for podUID := range vmi.Status.ActivePods { -+ _, err := m.hotplugManager.GetHotplugTargetPodPathOnHost(podUID) -+ if err == nil { -+ uid = podUID -+ cnt++ -+ } -+ } -+ if cnt == 1 { -+ return -+ } -+ // Either no pods, or multiple pods, skip. -+ return types.UID("") -+} -+ -+func GetMigrationAttachmentPodUID(vmi *v1.VirtualMachineInstance) (types.UID, bool) { -+ if attachmentPodUID := vmi.Status.MigrationState.TargetAttachmentPodUID; attachmentPodUID != types.UID("") { -+ return attachmentPodUID, true -+ } -+ return types.UID(""), false -+} -+ -+func VerifyHotplugChecksums(mounter HotplugMounter, vmi *v1.VirtualMachineInstance, sourceUID types.UID) error { -+ diskChecksums, err := mounter.ComputeChecksums(vmi, sourceUID) -+ if err != nil { -+ return fmt.Errorf("failed to compute hotplug container disk checksums: %s", err) -+ } -+ -+ for _, volumeStatus := range vmi.Status.VolumeStatus { -+ if volumeStatus.ContainerDiskVolume == nil || volumeStatus.HotplugVolume == nil { -+ continue -+ } -+ -+ expectedChecksum := volumeStatus.ContainerDiskVolume.Checksum -+ computedChecksum := diskChecksums.ContainerDiskChecksums[volumeStatus.Name] -+ if err := compareChecksums(expectedChecksum, computedChecksum); err != nil { -+ return fmt.Errorf("checksum error for hotplug volume %s: %w", volumeStatus.Name, err) -+ } -+ } -+ return nil -+} -diff --git a/pkg/virt-handler/container-disk/mount.go b/pkg/virt-handler/container-disk/mount.go -index 953c20f3af..d33a571495 100644 ---- a/pkg/virt-handler/container-disk/mount.go -+++ b/pkg/virt-handler/container-disk/mount.go -@@ -254,7 +254,7 @@ func (m *mounter) MountAndVerify(vmi *v1.VirtualMachineInstance) (map[string]*co - disksInfo := map[string]*containerdisk.DiskInfo{} - - for i, volume := range vmi.Spec.Volumes { -- if volume.ContainerDisk != nil { -+ if volume.ContainerDisk != nil && !volume.ContainerDisk.Hotpluggable { - diskTargetDir, err := containerdisk.GetDiskTargetDirFromHostView(vmi) - if err != nil { - return nil, err -@@ -296,7 +296,7 @@ func (m *mounter) MountAndVerify(vmi *v1.VirtualMachineInstance) (map[string]*co - } - - for i, volume := range vmi.Spec.Volumes { -- if volume.ContainerDisk != nil { -+ if volume.ContainerDisk != nil && !volume.ContainerDisk.Hotpluggable { - diskTargetDir, err := containerdisk.GetDiskTargetDirFromHostView(vmi) - if err != nil { - return nil, err -@@ -394,7 +394,7 @@ func (m *mounter) Unmount(vmi *v1.VirtualMachineInstance) error { - - func (m *mounter) ContainerDisksReady(vmi *v1.VirtualMachineInstance, notInitializedSince time.Time) (bool, error) { - for i, volume := range vmi.Spec.Volumes { -- if volume.ContainerDisk != nil { -+ if volume.ContainerDisk != nil && !volume.ContainerDisk.Hotpluggable { - _, err := m.socketPathGetter(vmi, i) - if err != nil { - log.DefaultLogger().Object(vmi).Reason(err).Infof("containerdisk %s not yet ready", volume.Name) -@@ -706,7 +706,7 @@ func (m *mounter) ComputeChecksums(vmi *v1.VirtualMachineInstance) (*DiskChecksu - - // compute for containerdisks - for i, volume := range vmi.Spec.Volumes { -- if volume.VolumeSource.ContainerDisk == nil { -+ if volume.VolumeSource.ContainerDisk == nil || volume.VolumeSource.ContainerDisk.Hotpluggable { - continue - } - -@@ -771,7 +771,7 @@ func VerifyChecksums(mounter Mounter, vmi *v1.VirtualMachineInstance) error { - - // verify containerdisks - for _, volumeStatus := range vmi.Status.VolumeStatus { -- if volumeStatus.ContainerDiskVolume == nil { -+ if volumeStatus.ContainerDiskVolume == nil || volumeStatus.HotplugVolume != nil { - continue - } - -diff --git a/pkg/virt-handler/hotplug-disk/mount.go b/pkg/virt-handler/hotplug-disk/mount.go -index 971c8d55fc..034c3d8526 100644 ---- a/pkg/virt-handler/hotplug-disk/mount.go -+++ b/pkg/virt-handler/hotplug-disk/mount.go -@@ -343,7 +343,7 @@ func (m *volumeMounter) mountFromPod(vmi *v1.VirtualMachineInstance, sourceUID t - return err - } - for _, volumeStatus := range vmi.Status.VolumeStatus { -- if volumeStatus.HotplugVolume == nil { -+ if volumeStatus.HotplugVolume == nil || volumeStatus.ContainerDiskVolume != nil { - // Skip non hotplug volumes - continue - } -@@ -649,7 +649,7 @@ func (m *volumeMounter) Unmount(vmi *v1.VirtualMachineInstance, cgroupManager cg - return err - } - for _, volumeStatus := range vmi.Status.VolumeStatus { -- if volumeStatus.HotplugVolume == nil { -+ if volumeStatus.HotplugVolume == nil || volumeStatus.ContainerDiskVolume != nil { - continue - } - var path *safepath.Path -diff --git a/pkg/virt-handler/isolation/detector.go b/pkg/virt-handler/isolation/detector.go -index f83f96ead4..5e38c6cedd 100644 ---- a/pkg/virt-handler/isolation/detector.go -+++ b/pkg/virt-handler/isolation/detector.go -@@ -24,6 +24,8 @@ package isolation - import ( - "fmt" - "net" -+ "os" -+ "path" - "runtime" - "syscall" - "time" -@@ -207,12 +209,45 @@ func setProcessMemoryLockRLimit(pid int, size int64) error { - return nil - } - -+type deferFunc func() -+ -+func (s *socketBasedIsolationDetector) socketHack(socket string) (sock net.Conn, deferFunc deferFunc, err error) { -+ fn := func() {} -+ if len([]rune(socket)) <= 108 { -+ sock, err = net.DialTimeout("unix", socket, time.Duration(isolationDialTimeout)*time.Second) -+ fn = func() { -+ if err == nil { -+ sock.Close() -+ } -+ } -+ return sock, fn, err -+ } -+ base := path.Base(socket) -+ newPath := fmt.Sprintf("/tmp/%s", base) -+ if err = os.Symlink(socket, newPath); err != nil { -+ return nil, fn, err -+ } -+ sock, err = net.DialTimeout("unix", newPath, time.Duration(isolationDialTimeout)*time.Second) -+ fn = func() { -+ if err == nil { -+ sock.Close() -+ } -+ os.Remove(newPath) -+ } -+ return sock, fn, err -+} -+ - func (s *socketBasedIsolationDetector) getPid(socket string) (int, error) { -- sock, err := net.DialTimeout("unix", socket, time.Duration(isolationDialTimeout)*time.Second) -+ sock, defFn, err := s.socketHack(socket) -+ defer defFn() - if err != nil { - return -1, err - } -- defer sock.Close() -+ //sock, err := net.DialTimeout("unix", socket, time.Duration(isolationDialTimeout)*time.Second) -+ //if err != nil { -+ // return -1, err -+ //} -+ //defer sock.Close() - - ufile, err := sock.(*net.UnixConn).File() - if err != nil { -diff --git a/pkg/virt-handler/virt-chroot/virt-chroot.go b/pkg/virt-handler/virt-chroot/virt-chroot.go -index 4160212b7b..580b788acc 100644 ---- a/pkg/virt-handler/virt-chroot/virt-chroot.go -+++ b/pkg/virt-handler/virt-chroot/virt-chroot.go -@@ -20,7 +20,10 @@ - package virt_chroot - - import ( -+ "bytes" -+ "fmt" - "os/exec" -+ "slices" - "strings" - - "kubevirt.io/kubevirt/pkg/safepath" -@@ -48,6 +51,49 @@ func MountChroot(sourcePath, targetPath *safepath.Path, ro bool) *exec.Cmd { - return UnsafeMountChroot(trimProcPrefix(sourcePath), trimProcPrefix(targetPath), ro) - } - -+func MountChrootWithOptions(sourcePath, targetPath *safepath.Path, mountOptions ...string) error { -+ args := append(getBaseArgs(), "mount") -+ remountArgs := slices.Clone(args) -+ -+ mountOptions = slices.DeleteFunc(mountOptions, func(s string) bool { -+ return s == "remount" -+ }) -+ if len(mountOptions) > 0 { -+ opts := strings.Join(mountOptions, ",") -+ remountOpts := "remount," + opts -+ args = append(args, "-o", opts) -+ remountArgs = append(remountArgs, "-o", remountOpts) -+ } -+ -+ sp := trimProcPrefix(sourcePath) -+ tp := trimProcPrefix(targetPath) -+ args = append(args, sp, tp) -+ remountArgs = append(remountArgs, sp, tp) -+ -+ stdout := new(bytes.Buffer) -+ stderr := new(bytes.Buffer) -+ -+ cmd := exec.Command(binaryPath, args...) -+ cmd.Stdout = stdout -+ cmd.Stderr = stderr -+ err := cmd.Run() -+ if err != nil { -+ return fmt.Errorf("mount failed: %w, stdout: %s, stderr: %s", err, stdout.String(), stderr.String()) -+ } -+ -+ stdout = new(bytes.Buffer) -+ stderr = new(bytes.Buffer) -+ -+ remountCmd := exec.Command(binaryPath, remountArgs...) -+ cmd.Stdout = stdout -+ cmd.Stderr = stderr -+ err = remountCmd.Run() -+ if err != nil { -+ return fmt.Errorf("mount failed: %w, stdout: %s, stderr: %s", err, stdout.String(), stderr.String()) -+ } -+ return nil -+} -+ - // Deprecated: UnsafeMountChroot is used to connect to code which needs to be refactored - // to handle mounts securely. - func UnsafeMountChroot(sourcePath, targetPath string, ro bool) *exec.Cmd { -diff --git a/pkg/virt-handler/vm.go b/pkg/virt-handler/vm.go -index 24352cf6e9..301d7b2249 100644 ---- a/pkg/virt-handler/vm.go -+++ b/pkg/virt-handler/vm.go -@@ -25,6 +25,7 @@ import ( - goerror "errors" - "fmt" - "io" -+ "maps" - "net" - "os" - "path/filepath" -@@ -247,6 +248,13 @@ func NewController( - vmiExpectations: controller.NewUIDTrackingControllerExpectations(controller.NewControllerExpectations()), - sriovHotplugExecutorPool: executor.NewRateLimitedExecutorPool(executor.NewExponentialLimitedBackoffCreator()), - ioErrorRetryManager: NewFailRetryManager("io-error-retry", 10*time.Second, 3*time.Minute, 30*time.Second), -+ -+ hotplugContainerDiskMounter: container_disk.NewHotplugMounter( -+ podIsolationDetector, -+ filepath.Join(virtPrivateDir, "hotplug-container-disk-mount-state"), -+ clusterConfig, -+ hotplugdisk.NewHotplugDiskManager(kubeletPodsDir), -+ ), - } - - _, err := vmiSourceInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{ -@@ -342,6 +350,8 @@ type VirtualMachineController struct { - hostCpuModel string - vmiExpectations *controller.UIDTrackingControllerExpectations - ioErrorRetryManager *FailRetryManager -+ -+ hotplugContainerDiskMounter container_disk.HotplugMounter - } - - type virtLauncherCriticalSecurebootError struct { -@@ -876,7 +886,15 @@ func (d *VirtualMachineController) updateHotplugVolumeStatus(vmi *v1.VirtualMach - needsRefresh := false - if volumeStatus.Target == "" { - needsRefresh = true -- mounted, err := d.hotplugVolumeMounter.IsMounted(vmi, volumeStatus.Name, volumeStatus.HotplugVolume.AttachPodUID) -+ var ( -+ mounted bool -+ err error -+ ) -+ if volumeStatus.ContainerDiskVolume != nil { -+ mounted, err = d.hotplugContainerDiskMounter.IsMounted(vmi, volumeStatus.Name) -+ } else { -+ mounted, err = d.hotplugVolumeMounter.IsMounted(vmi, volumeStatus.Name, volumeStatus.HotplugVolume.AttachPodUID) -+ } - if err != nil { - log.Log.Object(vmi).Errorf("error occurred while checking if volume is mounted: %v", err) - } -@@ -898,6 +916,7 @@ func (d *VirtualMachineController) updateHotplugVolumeStatus(vmi *v1.VirtualMach - volumeStatus.Reason = VolumeUnMountedFromPodReason - } - } -+ - } else { - // Successfully attached to VM. - volumeStatus.Phase = v1.VolumeReady -@@ -966,17 +985,28 @@ func (d *VirtualMachineController) updateChecksumInfo(vmi *v1.VirtualMachineInst - if err != nil { - return err - } -+ hotplugDiskChecksums, err := d.hotplugContainerDiskMounter.ComputeChecksums(vmi, "") -+ if goerror.Is(err, container_disk.ErrDiskContainerGone) { -+ log.Log.Errorf("cannot compute checksums as hotplug containerdisk containers seem to have been terminated") -+ return nil -+ } -+ if err != nil { -+ return err -+ } - - // containerdisks - for i := range vmi.Status.VolumeStatus { - checksum, exists := diskChecksums.ContainerDiskChecksums[vmi.Status.VolumeStatus[i].Name] -- if !exists { -- // not a containerdisk -- continue -+ if exists { -+ vmi.Status.VolumeStatus[i].ContainerDiskVolume = &v1.ContainerDiskInfo{ -+ Checksum: checksum, -+ } - } -- -- vmi.Status.VolumeStatus[i].ContainerDiskVolume = &v1.ContainerDiskInfo{ -- Checksum: checksum, -+ hotplugChecksum, hotplugExists := hotplugDiskChecksums.ContainerDiskChecksums[vmi.Status.VolumeStatus[i].Name] -+ if hotplugExists { -+ vmi.Status.VolumeStatus[i].ContainerDiskVolume = &v1.ContainerDiskInfo{ -+ Checksum: hotplugChecksum, -+ } - } - } - -@@ -2178,6 +2208,11 @@ func (d *VirtualMachineController) processVmCleanup(vmi *v1.VirtualMachineInstan - return err - } - -+ err := d.hotplugContainerDiskMounter.UmountAll(vmi) -+ if err != nil { -+ return err -+ } -+ - // UnmountAll does the cleanup on the "best effort" basis: it is - // safe to pass a nil cgroupManager. - cgroupManager, _ := getCgroupManager(vmi) -@@ -2808,7 +2843,6 @@ func (d *VirtualMachineController) vmUpdateHelperMigrationTarget(origVMI *v1.Vir - d.Queue.AddAfter(controller.VirtualMachineInstanceKey(vmi), time.Second*1) - return nil - } -- - // Verify container disks checksum - err = container_disk.VerifyChecksums(d.containerDiskMounter, vmi) - switch { -@@ -2823,11 +2857,41 @@ func (d *VirtualMachineController) vmUpdateHelperMigrationTarget(origVMI *v1.Vir - return err - } - -+ if uid, found := container_disk.GetMigrationAttachmentPodUID(vmi); found { -+ if ready, err := d.hotplugContainerDiskMounter.ContainerDisksReady(vmi, info.NotInitializedSince, uid); !ready { -+ if err != nil { -+ return err -+ } -+ d.Queue.AddAfter(controller.VirtualMachineInstanceKey(vmi), time.Second*1) -+ return nil -+ } -+ // Verify hotplug container disks checksum -+ err = container_disk.VerifyHotplugChecksums(d.hotplugContainerDiskMounter, vmi, uid) -+ switch { -+ case goerror.Is(err, container_disk.ErrChecksumMissing): -+ // wait for checksum to be computed by the source virt-handler -+ return err -+ case goerror.Is(err, container_disk.ErrChecksumMismatch): -+ log.Log.Object(vmi).Infof("HotplugContainerdisk checksum mismatch, terminating target pod: %s", err) -+ d.recorder.Event(vmi, k8sv1.EventTypeNormal, "HotplugContainerDiskFailedChecksum", "Aborting migration as the source and target containerdisks do not match") -+ return client.SignalTargetPodCleanup(vmi) -+ case err != nil: -+ return err -+ } -+ } -+ - // Mount container disks - disksInfo, err := d.containerDiskMounter.MountAndVerify(vmi) - if err != nil { - return err - } -+ if uid, found := container_disk.GetMigrationAttachmentPodUID(vmi); found { -+ hotplugDiskInfo, err := d.hotplugContainerDiskMounter.MoundAndVerifyFromPod(vmi, uid) -+ if err != nil { -+ return err -+ } -+ maps.Copy(disksInfo, hotplugDiskInfo) -+ } - - // Mount hotplug disks - if attachmentPodUID := vmi.Status.MigrationState.TargetAttachmentPodUID; attachmentPodUID != types.UID("") { -@@ -3051,6 +3115,13 @@ func (d *VirtualMachineController) vmUpdateHelperDefault(origVMI *v1.VirtualMach - if err != nil { - return err - } -+ if ready, err := d.hotplugContainerDiskMounter.ContainerDisksReady(vmi, info.NotInitializedSince, ""); ready && err != nil { -+ hotplugDiskInfo, err := d.hotplugContainerDiskMounter.MountAndVerify(vmi) -+ if err != nil { -+ return err -+ } -+ maps.Copy(disksInfo, hotplugDiskInfo) -+ } - - // Try to mount hotplug volume if there is any during startup. - if err := d.hotplugVolumeMounter.Mount(vmi, cgroupManager); err != nil { -@@ -3138,6 +3209,11 @@ func (d *VirtualMachineController) vmUpdateHelperDefault(origVMI *v1.VirtualMach - log.Log.Object(vmi).Error(err.Error()) - } - -+ hotplugDiskInfo, err := d.hotplugContainerDiskMounter.MountAndVerify(vmi) -+ if err != nil { -+ return err -+ } -+ maps.Copy(disksInfo, hotplugDiskInfo) - if err := d.hotplugVolumeMounter.Mount(vmi, cgroupManager); err != nil { - return err - } -@@ -3215,6 +3291,9 @@ func (d *VirtualMachineController) vmUpdateHelperDefault(origVMI *v1.VirtualMach - - if vmi.IsRunning() { - // Umount any disks no longer mounted -+ if err := d.hotplugContainerDiskMounter.Umount(vmi); err != nil { -+ return err -+ } - if err := d.hotplugVolumeMounter.Unmount(vmi, cgroupManager); err != nil { - return err - } -diff --git a/pkg/virt-launcher/virtwrap/converter/converter.go b/pkg/virt-launcher/virtwrap/converter/converter.go -index 3318c1c466..393415c36c 100644 ---- a/pkg/virt-launcher/virtwrap/converter/converter.go -+++ b/pkg/virt-launcher/virtwrap/converter/converter.go -@@ -649,6 +649,9 @@ func Convert_v1_Hotplug_Volume_To_api_Disk(source *v1.Volume, disk *api.Disk, c - if source.DataVolume != nil { - return Convert_v1_Hotplug_DataVolume_To_api_Disk(source.Name, disk, c) - } -+ if source.ContainerDisk != nil { -+ return Convert_v1_Hotplug_ContainerDisk_To_api_Disk(source.Name, disk, c) -+ } - return fmt.Errorf("hotplug disk %s references an unsupported source", disk.Alias.GetName()) - } - -@@ -690,6 +693,10 @@ func GetHotplugBlockDeviceVolumePath(volumeName string) string { - return filepath.Join(string(filepath.Separator), "var", "run", "kubevirt", "hotplug-disks", volumeName) - } - -+func GetHotplugContainerDiskPath(volumeName string) string { -+ return filepath.Join(string(filepath.Separator), "var", "run", "kubevirt", "hotplug-disks", fmt.Sprintf("%s.img", volumeName)) -+} -+ - func Convert_v1_PersistentVolumeClaim_To_api_Disk(name string, disk *api.Disk, c *ConverterContext) error { - if c.IsBlockPVC[name] { - return Convert_v1_BlockVolumeSource_To_api_Disk(name, disk, c.VolumesDiscardIgnore) -@@ -768,6 +775,37 @@ func Convert_v1_Hotplug_BlockVolumeSource_To_api_Disk(volumeName string, disk *a - return nil - } - -+var ErrHotplugContainerDiskInfoNotProvided = errors.New("hotplug container disk info not provided") -+ -+func Convert_v1_Hotplug_ContainerDisk_To_api_Disk(volumeName string, disk *api.Disk, c *ConverterContext) error { -+ if disk.Type == "lun" { -+ return fmt.Errorf(deviceTypeNotCompatibleFmt, disk.Alias.GetName()) -+ } -+ info := c.DisksInfo[volumeName] -+ if info == nil { -+ return fmt.Errorf("no disk info provided for volume %s: %w", volumeName, ErrHotplugContainerDiskInfoNotProvided) -+ } -+ -+ disk.Type = "file" -+ disk.Driver.Type = info.Format -+ disk.Driver.ErrorPolicy = v1.DiskErrorPolicyStop -+ disk.ReadOnly = toApiReadOnly(true) -+ if !contains(c.VolumesDiscardIgnore, volumeName) { -+ disk.Driver.Discard = "unmap" -+ } -+ disk.Source.File = GetHotplugContainerDiskPath(volumeName) -+ disk.BackingStore = &api.BackingStore{ -+ Format: &api.BackingStoreFormat{}, -+ Source: &api.DiskSource{}, -+ } -+ -+ //disk.BackingStore.Format.Type = info.Format -+ //disk.BackingStore.Source.File = info.BackingFile -+ //disk.BackingStore.Type = "file" -+ -+ return nil -+} -+ - func Convert_v1_HostDisk_To_api_Disk(volumeName string, path string, disk *api.Disk) error { - disk.Type = "file" - disk.Driver.Type = "raw" -@@ -1581,6 +1619,10 @@ func Convert_v1_VirtualMachineInstance_To_api_Domain(vmi *v1.VirtualMachineInsta - err = Convert_v1_Volume_To_api_Disk(volume, &newDisk, c, volumeIndices[disk.Name]) - } else { - err = Convert_v1_Hotplug_Volume_To_api_Disk(volume, &newDisk, c) -+ if errors.Is(err, ErrHotplugContainerDiskInfoNotProvided) { -+ log.DefaultLogger().Warningf("Hotplug container disk info not provided. Skip hotplug disk %s", disk.Name) -+ continue -+ } - } - if err != nil { - return err -diff --git a/pkg/virt-launcher/virtwrap/live-migration-source.go b/pkg/virt-launcher/virtwrap/live-migration-source.go -index d8b777e5fb..f580d06e52 100644 ---- a/pkg/virt-launcher/virtwrap/live-migration-source.go -+++ b/pkg/virt-launcher/virtwrap/live-migration-source.go -@@ -289,8 +289,10 @@ func classifyVolumesForMigration(vmi *v1.VirtualMachineInstance) *migrationDisks - - case volSrc.ConfigMap != nil || volSrc.Secret != nil || volSrc.DownwardAPI != nil || - volSrc.ServiceAccount != nil || volSrc.CloudInitNoCloud != nil || -- volSrc.CloudInitConfigDrive != nil || volSrc.ContainerDisk != nil: -+ volSrc.CloudInitConfigDrive != nil || (volSrc.ContainerDisk != nil && !volSrc.ContainerDisk.Hotpluggable): - disks.generated[volume.Name] = true -+ case volSrc.ContainerDisk != nil && volSrc.ContainerDisk.Hotpluggable: -+ disks.shared[volume.Name] = true - } - } - -diff --git a/pkg/virt-launcher/virtwrap/manager.go b/pkg/virt-launcher/virtwrap/manager.go -index 4a1d22de46..cddee4f199 100644 ---- a/pkg/virt-launcher/virtwrap/manager.go -+++ b/pkg/virt-launcher/virtwrap/manager.go -@@ -32,6 +32,7 @@ import ( - "errors" - "fmt" - "io" -+ "maps" - "os" - "os/exec" - "path/filepath" -@@ -1029,9 +1030,7 @@ func (l *LibvirtDomainManager) generateConverterContext(vmi *v1.VirtualMachineIn - // Add preallocated and thick-provisioned volumes for which we need to avoid the discard=unmap option - c.VolumesDiscardIgnore = options.PreallocatedVolumes - -- if len(options.DisksInfo) > 0 { -- l.disksInfo = options.DisksInfo -- } -+ maps.Copy(l.disksInfo, options.DisksInfo) - - if options.GetClusterConfig() != nil { - c.ExpandDisksEnabled = options.GetClusterConfig().GetExpandDisksEnabled() -diff --git a/pkg/virt-operator/resource/apply/BUILD.bazel b/pkg/virt-operator/resource/apply/BUILD.bazel -index f6bd9bd4f1..fe6ab54f8c 100644 ---- a/pkg/virt-operator/resource/apply/BUILD.bazel -+++ b/pkg/virt-operator/resource/apply/BUILD.bazel -@@ -4,7 +4,6 @@ go_library( - name = "go_default_library", - srcs = [ - "admissionregistration.go", -- "apiservices.go", - "apps.go", - "certificates.go", - "core.go", -@@ -65,7 +64,6 @@ go_library( - "//vendor/k8s.io/client-go/tools/cache:go_default_library", - "//vendor/k8s.io/client-go/tools/record:go_default_library", - "//vendor/k8s.io/client-go/util/workqueue:go_default_library", -- "//vendor/k8s.io/kube-aggregator/pkg/apis/apiregistration/v1:go_default_library", - "//vendor/k8s.io/utils/pointer:go_default_library", - ], - ) -diff --git a/pkg/virt-operator/resource/generate/components/BUILD.bazel b/pkg/virt-operator/resource/generate/components/BUILD.bazel -index 70d2da0897..affcd3fecd 100644 ---- a/pkg/virt-operator/resource/generate/components/BUILD.bazel -+++ b/pkg/virt-operator/resource/generate/components/BUILD.bazel -@@ -3,7 +3,6 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") - go_library( - name = "go_default_library", - srcs = [ -- "apiservices.go", - "crds.go", - "daemonsets.go", - "deployments.go", -@@ -62,7 +61,6 @@ go_library( - "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/util/intstr:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/util/yaml:go_default_library", -- "//vendor/k8s.io/kube-aggregator/pkg/apis/apiregistration/v1:go_default_library", - "//vendor/k8s.io/utils/pointer:go_default_library", - ], - ) -@@ -70,7 +68,6 @@ go_library( - go_test( - name = "go_default_test", - srcs = [ -- "apiservices_test.go", - "components_suite_test.go", - "crds_test.go", - "deployments_test.go", -@@ -85,7 +82,6 @@ go_test( - deps = [ - "//pkg/certificates/bootstrap:go_default_library", - "//pkg/certificates/triple/cert:go_default_library", -- "//staging/src/kubevirt.io/api/core/v1:go_default_library", - "//staging/src/kubevirt.io/client-go/testutils:go_default_library", - "//vendor/github.com/onsi/ginkgo/v2:go_default_library", - "//vendor/github.com/onsi/gomega:go_default_library", -diff --git a/pkg/virt-operator/resource/generate/components/validations_generated.go b/pkg/virt-operator/resource/generate/components/validations_generated.go -index 4913dbead0..42225780ba 100644 ---- a/pkg/virt-operator/resource/generate/components/validations_generated.go -+++ b/pkg/virt-operator/resource/generate/components/validations_generated.go -@@ -7723,6 +7723,8 @@ var CRDsValidation map[string]string = map[string]string{ - ContainerDisk references a docker image, embedding a qcow or raw disk. - More info: https://kubevirt.gitbooks.io/user-guide/registry-disk.html - properties: -+ hotpluggable: -+ type: boolean - image: - description: Image is the name of the image with the embedded - disk. -@@ -8355,6 +8357,35 @@ var CRDsValidation map[string]string = map[string]string{ - description: VolumeSource represents the source of the volume - to map to the disk. - properties: -+ containerDisk: -+ description: Represents a docker image with an embedded disk. -+ properties: -+ hotpluggable: -+ type: boolean -+ image: -+ description: Image is the name of the image with the embedded -+ disk. -+ type: string -+ imagePullPolicy: -+ description: |- -+ Image pull policy. -+ One of Always, Never, IfNotPresent. -+ Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. -+ Cannot be updated. -+ More info: https://kubernetes.io/docs/concepts/containers/images#updating-images -+ type: string -+ imagePullSecret: -+ description: ImagePullSecret is the name of the Docker -+ registry secret required to pull the image. The secret -+ must already exist. -+ type: string -+ path: -+ description: Path defines the path to disk file in the -+ container -+ type: string -+ required: -+ - image -+ type: object - dataVolume: - description: |- - DataVolume represents the dynamic creation a PVC for this volume as well as -@@ -12768,6 +12799,8 @@ var CRDsValidation map[string]string = map[string]string{ - ContainerDisk references a docker image, embedding a qcow or raw disk. - More info: https://kubevirt.gitbooks.io/user-guide/registry-disk.html - properties: -+ hotpluggable: -+ type: boolean - image: - description: Image is the name of the image with the embedded - disk. -@@ -18328,6 +18361,8 @@ var CRDsValidation map[string]string = map[string]string{ - ContainerDisk references a docker image, embedding a qcow or raw disk. - More info: https://kubevirt.gitbooks.io/user-guide/registry-disk.html - properties: -+ hotpluggable: -+ type: boolean - image: - description: Image is the name of the image with the embedded - disk. -@@ -22835,6 +22870,8 @@ var CRDsValidation map[string]string = map[string]string{ - ContainerDisk references a docker image, embedding a qcow or raw disk. - More info: https://kubevirt.gitbooks.io/user-guide/registry-disk.html - properties: -+ hotpluggable: -+ type: boolean - image: - description: Image is the name of the image with - the embedded disk. -@@ -28015,6 +28052,8 @@ var CRDsValidation map[string]string = map[string]string{ - ContainerDisk references a docker image, embedding a qcow or raw disk. - More info: https://kubevirt.gitbooks.io/user-guide/registry-disk.html - properties: -+ hotpluggable: -+ type: boolean - image: - description: Image is the name of the image - with the embedded disk. -@@ -28673,6 +28712,36 @@ var CRDsValidation map[string]string = map[string]string{ - description: VolumeSource represents the source of - the volume to map to the disk. - properties: -+ containerDisk: -+ description: Represents a docker image with an -+ embedded disk. -+ properties: -+ hotpluggable: -+ type: boolean -+ image: -+ description: Image is the name of the image -+ with the embedded disk. -+ type: string -+ imagePullPolicy: -+ description: |- -+ Image pull policy. -+ One of Always, Never, IfNotPresent. -+ Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. -+ Cannot be updated. -+ More info: https://kubernetes.io/docs/concepts/containers/images#updating-images -+ type: string -+ imagePullSecret: -+ description: ImagePullSecret is the name of -+ the Docker registry secret required to pull -+ the image. The secret must already exist. -+ type: string -+ path: -+ description: Path defines the path to disk -+ file in the container -+ type: string -+ required: -+ - image -+ type: object - dataVolume: - description: |- - DataVolume represents the dynamic creation a PVC for this volume as well as -diff --git a/pkg/virt-operator/resource/generate/install/generated_mock_strategy.go b/pkg/virt-operator/resource/generate/install/generated_mock_strategy.go -index 5f1e9a3121..1fa1416af0 100644 ---- a/pkg/virt-operator/resource/generate/install/generated_mock_strategy.go -+++ b/pkg/virt-operator/resource/generate/install/generated_mock_strategy.go -@@ -241,16 +241,6 @@ func (_mr *_MockStrategyInterfaceRecorder) MutatingWebhookConfigurations() *gomo - return _mr.mock.ctrl.RecordCall(_mr.mock, "MutatingWebhookConfigurations") - } - --func (_m *MockStrategyInterface) APIServices() []*v18.APIService { -- ret := _m.ctrl.Call(_m, "APIServices") -- ret0, _ := ret[0].([]*v18.APIService) -- return ret0 --} -- --func (_mr *_MockStrategyInterfaceRecorder) APIServices() *gomock.Call { -- return _mr.mock.ctrl.RecordCall(_mr.mock, "APIServices") --} -- - func (_m *MockStrategyInterface) CertificateSecrets() []*v14.Secret { - ret := _m.ctrl.Call(_m, "CertificateSecrets") - ret0, _ := ret[0].([]*v14.Secret) -diff --git a/pkg/virt-operator/resource/generate/rbac/exportproxy.go b/pkg/virt-operator/resource/generate/rbac/exportproxy.go -index ebc9f2adbd..a0dc0586b4 100644 ---- a/pkg/virt-operator/resource/generate/rbac/exportproxy.go -+++ b/pkg/virt-operator/resource/generate/rbac/exportproxy.go -@@ -23,6 +23,7 @@ import ( - rbacv1 "k8s.io/api/rbac/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" -+ - "kubevirt.io/kubevirt/pkg/virt-operator/resource/generate/components" - - virtv1 "kubevirt.io/api/core/v1" -diff --git a/staging/src/kubevirt.io/api/apitesting/testdata/HEAD/kubevirt.io.v1.VirtualMachine.json b/staging/src/kubevirt.io/api/apitesting/testdata/HEAD/kubevirt.io.v1.VirtualMachine.json -index b651173636..3453dfb0da 100644 ---- a/staging/src/kubevirt.io/api/apitesting/testdata/HEAD/kubevirt.io.v1.VirtualMachine.json -+++ b/staging/src/kubevirt.io/api/apitesting/testdata/HEAD/kubevirt.io.v1.VirtualMachine.json -@@ -754,7 +754,8 @@ - "image": "imageValue", - "imagePullSecret": "imagePullSecretValue", - "path": "pathValue", -- "imagePullPolicy": "imagePullPolicyValue" -+ "imagePullPolicy": "imagePullPolicyValue", -+ "hotpluggable": true - }, - "ephemeral": { - "persistentVolumeClaim": { -@@ -1209,6 +1210,13 @@ - "dataVolume": { - "name": "nameValue", - "hotpluggable": true -+ }, -+ "containerDisk": { -+ "image": "imageValue", -+ "imagePullSecret": "imagePullSecretValue", -+ "path": "pathValue", -+ "imagePullPolicy": "imagePullPolicyValue", -+ "hotpluggable": true - } - }, - "dryRun": [ -diff --git a/staging/src/kubevirt.io/api/apitesting/testdata/HEAD/kubevirt.io.v1.VirtualMachine.yaml b/staging/src/kubevirt.io/api/apitesting/testdata/HEAD/kubevirt.io.v1.VirtualMachine.yaml -index 53dfdacc3b..8b23193158 100644 ---- a/staging/src/kubevirt.io/api/apitesting/testdata/HEAD/kubevirt.io.v1.VirtualMachine.yaml -+++ b/staging/src/kubevirt.io/api/apitesting/testdata/HEAD/kubevirt.io.v1.VirtualMachine.yaml -@@ -719,6 +719,7 @@ spec: - optional: true - volumeLabel: volumeLabelValue - containerDisk: -+ hotpluggable: true - image: imageValue - imagePullPolicy: imagePullPolicyValue - imagePullSecret: imagePullSecretValue -@@ -838,6 +839,12 @@ status: - - dryRunValue - name: nameValue - volumeSource: -+ containerDisk: -+ hotpluggable: true -+ image: imageValue -+ imagePullPolicy: imagePullPolicyValue -+ imagePullSecret: imagePullSecretValue -+ path: pathValue - dataVolume: - hotpluggable: true - name: nameValue -diff --git a/staging/src/kubevirt.io/api/apitesting/testdata/HEAD/kubevirt.io.v1.VirtualMachineInstance.json b/staging/src/kubevirt.io/api/apitesting/testdata/HEAD/kubevirt.io.v1.VirtualMachineInstance.json -index 3be904512c..f595798e89 100644 ---- a/staging/src/kubevirt.io/api/apitesting/testdata/HEAD/kubevirt.io.v1.VirtualMachineInstance.json -+++ b/staging/src/kubevirt.io/api/apitesting/testdata/HEAD/kubevirt.io.v1.VirtualMachineInstance.json -@@ -694,7 +694,8 @@ - "image": "imageValue", - "imagePullSecret": "imagePullSecretValue", - "path": "pathValue", -- "imagePullPolicy": "imagePullPolicyValue" -+ "imagePullPolicy": "imagePullPolicyValue", -+ "hotpluggable": true - }, - "ephemeral": { - "persistentVolumeClaim": { -diff --git a/staging/src/kubevirt.io/api/apitesting/testdata/HEAD/kubevirt.io.v1.VirtualMachineInstance.yaml b/staging/src/kubevirt.io/api/apitesting/testdata/HEAD/kubevirt.io.v1.VirtualMachineInstance.yaml -index 6fd2ab6523..b6457ec94d 100644 ---- a/staging/src/kubevirt.io/api/apitesting/testdata/HEAD/kubevirt.io.v1.VirtualMachineInstance.yaml -+++ b/staging/src/kubevirt.io/api/apitesting/testdata/HEAD/kubevirt.io.v1.VirtualMachineInstance.yaml -@@ -524,6 +524,7 @@ spec: - optional: true - volumeLabel: volumeLabelValue - containerDisk: -+ hotpluggable: true - image: imageValue - imagePullPolicy: imagePullPolicyValue - imagePullSecret: imagePullSecretValue -diff --git a/staging/src/kubevirt.io/api/core/v1/BUILD.bazel b/staging/src/kubevirt.io/api/core/v1/BUILD.bazel -index f8615293a3..0c6c166985 100644 ---- a/staging/src/kubevirt.io/api/core/v1/BUILD.bazel -+++ b/staging/src/kubevirt.io/api/core/v1/BUILD.bazel -@@ -28,7 +28,6 @@ go_library( - "//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/types:go_default_library", - "//vendor/k8s.io/utils/net:go_default_library", -- "//vendor/k8s.io/utils/pointer:go_default_library", - "//vendor/kubevirt.io/containerized-data-importer-api/pkg/apis/core/v1beta1:go_default_library", - ], - ) -diff --git a/staging/src/kubevirt.io/api/core/v1/deepcopy_generated.go b/staging/src/kubevirt.io/api/core/v1/deepcopy_generated.go -index abd5a495d6..7372b22a9a 100644 ---- a/staging/src/kubevirt.io/api/core/v1/deepcopy_generated.go -+++ b/staging/src/kubevirt.io/api/core/v1/deepcopy_generated.go -@@ -1948,6 +1948,11 @@ func (in *HotplugVolumeSource) DeepCopyInto(out *HotplugVolumeSource) { - *out = new(DataVolumeSource) - **out = **in - } -+ if in.ContainerDisk != nil { -+ in, out := &in.ContainerDisk, &out.ContainerDisk -+ *out = new(ContainerDiskSource) -+ **out = **in -+ } - return - } - -diff --git a/staging/src/kubevirt.io/api/core/v1/schema.go b/staging/src/kubevirt.io/api/core/v1/schema.go -index 29aa3932d3..302ed9ffde 100644 ---- a/staging/src/kubevirt.io/api/core/v1/schema.go -+++ b/staging/src/kubevirt.io/api/core/v1/schema.go -@@ -854,6 +854,8 @@ type HotplugVolumeSource struct { - // the process of populating that PVC with a disk image. - // +optional - DataVolume *DataVolumeSource `json:"dataVolume,omitempty"` -+ -+ ContainerDisk *ContainerDiskSource `json:"containerDisk,omitempty"` - } - - type DataVolumeSource struct { -@@ -911,6 +913,8 @@ type ContainerDiskSource struct { - // More info: https://kubernetes.io/docs/concepts/containers/images#updating-images - // +optional - ImagePullPolicy v1.PullPolicy `json:"imagePullPolicy,omitempty"` -+ -+ Hotpluggable bool `json:"hotpluggable,omitempty"` - } - - // Exactly one of its members must be set. -diff --git a/staging/src/kubevirt.io/client-go/api/openapi_generated.go b/staging/src/kubevirt.io/client-go/api/openapi_generated.go -index cc2d743492..b982b1620c 100644 ---- a/staging/src/kubevirt.io/client-go/api/openapi_generated.go -+++ b/staging/src/kubevirt.io/client-go/api/openapi_generated.go -@@ -17772,6 +17772,12 @@ func schema_kubevirtio_api_core_v1_ContainerDiskSource(ref common.ReferenceCallb - Enum: []interface{}{"Always", "IfNotPresent", "Never"}, - }, - }, -+ "hotpluggable": { -+ SchemaProps: spec.SchemaProps{ -+ Type: []string{"boolean"}, -+ Format: "", -+ }, -+ }, - }, - Required: []string{"image"}, - }, -@@ -19645,11 +19651,16 @@ func schema_kubevirtio_api_core_v1_HotplugVolumeSource(ref common.ReferenceCallb - Ref: ref("kubevirt.io/api/core/v1.DataVolumeSource"), - }, - }, -+ "containerDisk": { -+ SchemaProps: spec.SchemaProps{ -+ Ref: ref("kubevirt.io/api/core/v1.ContainerDiskSource"), -+ }, -+ }, - }, - }, - }, - Dependencies: []string{ -- "kubevirt.io/api/core/v1.DataVolumeSource", "kubevirt.io/api/core/v1.PersistentVolumeClaimVolumeSource"}, -+ "kubevirt.io/api/core/v1.ContainerDiskSource", "kubevirt.io/api/core/v1.DataVolumeSource", "kubevirt.io/api/core/v1.PersistentVolumeClaimVolumeSource"}, - } - } - diff --git a/images/virt-artifact/patches/032-fix-virt-controller-tests.patch b/images/virt-artifact/patches/032-fix-virt-controller-tests.patch deleted file mode 100644 index 6077185764..0000000000 --- a/images/virt-artifact/patches/032-fix-virt-controller-tests.patch +++ /dev/null @@ -1,232 +0,0 @@ -diff --git a/pkg/virt-controller/services/renderresources_test.go b/pkg/virt-controller/services/renderresources_test.go -index 3b78f5b53d..5e4c32d3da 100644 ---- a/pkg/virt-controller/services/renderresources_test.go -+++ b/pkg/virt-controller/services/renderresources_test.go -@@ -321,7 +321,7 @@ var _ = Describe("Resource pod spec renderer", func() { - }) - }) - -- It("WithSEV option adds ", func() { -+ PIt("WithSEV option adds ", func() { - sevResourceKey := kubev1.ResourceName("devices.kubevirt.io/sev") - rr = NewResourceRenderer(nil, nil, WithSEV()) - Expect(rr.Requests()).To(Equal(kubev1.ResourceList{ -diff --git a/pkg/virt-controller/watch/application_test.go b/pkg/virt-controller/watch/application_test.go -index 3c4ec1cdc6..61febcb0b8 100644 ---- a/pkg/virt-controller/watch/application_test.go -+++ b/pkg/virt-controller/watch/application_test.go -@@ -92,6 +92,7 @@ var _ = Describe("Application", func() { - pdbInformer, _ := testutils.NewFakeInformerFor(&policyv1.PodDisruptionBudget{}) - migrationPolicyInformer, _ := testutils.NewFakeInformerFor(&migrationsv1.MigrationPolicy{}) - podInformer, _ := testutils.NewFakeInformerFor(&k8sv1.Pod{}) -+ nsInformer, _ := testutils.NewFakeInformerFor(&k8sv1.Namespace{}) - resourceQuotaInformer, _ := testutils.NewFakeInformerFor(&k8sv1.ResourceQuota{}) - pvcInformer, _ := testutils.NewFakeInformerFor(&k8sv1.PersistentVolumeClaim{}) - namespaceInformer, _ := testutils.NewFakeInformerFor(&k8sv1.Namespace{}) -@@ -141,6 +142,9 @@ var _ = Describe("Application", func() { - cdiConfigInformer, - config, - topology.NewTopologyHinter(&cache.FakeCustomStore{}, &cache.FakeCustomStore{}, nil), -+ podInformer, -+ nsInformer, -+ nodeInformer, - ) - app.rsController, _ = NewVMIReplicaSet(vmiInformer, rsInformer, recorder, virtClient, uint(10)) - app.vmController, _ = NewVMController(vmiInformer, -@@ -180,7 +184,8 @@ var _ = Describe("Application", func() { - CRDInformer: crdInformer, - DVInformer: dvInformer, - Recorder: recorder, -- ResyncPeriod: 60 * time.Second, -+ // The specified resyncPeriod 1m0s is invalid because this shared informer doesn't support resyncing. -+ // ResyncPeriod: 60 * time.Second, - } - _ = app.snapshotController.Init() - app.restoreController = &snapshot.VMRestoreController{ -diff --git a/pkg/virt-controller/watch/vmi_test.go b/pkg/virt-controller/watch/vmi_test.go -index 8f6df6d482..b4b76bd73e 100644 ---- a/pkg/virt-controller/watch/vmi_test.go -+++ b/pkg/virt-controller/watch/vmi_test.go -@@ -96,6 +96,7 @@ var _ = Describe("VirtualMachineInstance watcher", func() { - var storageClassInformer cache.SharedIndexInformer - var rqInformer cache.SharedIndexInformer - var nsInformer cache.SharedIndexInformer -+ var nodeInformer cache.SharedIndexInformer - var kvInformer cache.SharedIndexInformer - - var dataVolumeInformer cache.SharedIndexInformer -@@ -276,7 +277,9 @@ var _ = Describe("VirtualMachineInstance watcher", func() { - cdiInformer, _ = testutils.NewFakeInformerFor(&cdiv1.CDIConfig{}) - cdiConfigInformer, _ = testutils.NewFakeInformerFor(&cdiv1.CDIConfig{}) - rqInformer, _ = testutils.NewFakeInformerFor(&k8sv1.ResourceQuota{}) -+ podInformer, _ = testutils.NewFakeInformerFor(&k8sv1.Pod{}) - nsInformer, _ = testutils.NewFakeInformerFor(&k8sv1.Namespace{}) -+ nodeInformer, _ = testutils.NewFakeInformerFor(&k8sv1.Node{}) - controller, _ = NewVMIController( - services.NewTemplateService("a", 240, "b", "c", "d", "e", "f", "g", pvcInformer.GetStore(), virtClient, config, qemuGid, "h", rqInformer.GetStore(), nsInformer.GetStore()), - vmiInformer, -@@ -292,6 +295,9 @@ var _ = Describe("VirtualMachineInstance watcher", func() { - cdiConfigInformer, - config, - topology.NewTopologyHinter(&cache.FakeCustomStore{}, &cache.FakeCustomStore{}, config), -+ podInformer, -+ nsInformer, -+ nodeInformer, - ) - // Wrap our workqueue to have a way to detect when we are done processing updates - mockQueue = testutils.NewMockWorkQueue(controller.Queue) -@@ -327,6 +333,7 @@ var _ = Describe("VirtualMachineInstance watcher", func() { - Expect(podInformer.GetIndexer().Add(pod)).To(Succeed()) - _, err := kubeClient.CoreV1().Pods(pod.Namespace).Create(context.Background(), pod, metav1.CreateOptions{}) - Expect(err).ToNot(HaveOccurred()) -+ Expect(nodeInformer.GetIndexer().Add(NewNodeForPod(pod))).To(Succeed()) - } - - addDataVolumePVC := func(dvPVC *k8sv1.PersistentVolumeClaim) { -@@ -949,7 +956,7 @@ var _ = Describe("VirtualMachineInstance watcher", func() { - Entry("in scheduled state", virtv1.Scheduled), - Entry("in scheduling state", virtv1.Scheduling), - ) -- It("should not try to delete a pod again, which is already marked for deletion and go to failed state, when in scheduling state", func() { -+ PIt("should not try to delete a pod again, which is already marked for deletion and go to failed state, when in scheduling state", func() { - vmi := NewPendingVirtualMachine("testvmi") - setReadyCondition(vmi, k8sv1.ConditionFalse, virtv1.GuestNotRunningReason) - -@@ -1509,7 +1516,7 @@ var _ = Describe("VirtualMachineInstance watcher", func() { - Expect(err).ToNot(HaveOccurred()) - Expect(*updatedVmi.Status.QOSClass).To(Equal(k8sv1.PodQOSGuaranteed)) - }) -- It("should update the virtual machine to scheduled if pod is ready, triggered by pod change", func() { -+ PIt("should update the virtual machine to scheduled if pod is ready, triggered by pod change", func() { - vmi := NewPendingVirtualMachine("testvmi") - setReadyCondition(vmi, k8sv1.ConditionFalse, virtv1.GuestNotRunningReason) - vmi.Status.Phase = virtv1.Scheduling -@@ -1530,7 +1537,7 @@ var _ = Describe("VirtualMachineInstance watcher", func() { - controller.Execute() - expectVMIScheduledState(vmi) - }) -- It("should update the virtual machine to failed if pod was not ready, triggered by pod delete", func() { -+ PIt("should update the virtual machine to failed if pod was not ready, triggered by pod delete", func() { - vmi := NewPendingVirtualMachine("testvmi") - setReadyCondition(vmi, k8sv1.ConditionFalse, virtv1.GuestNotRunningReason) - pod := NewPodForVirtualMachine(vmi, k8sv1.PodPending) -@@ -1648,9 +1655,12 @@ var _ = Describe("VirtualMachineInstance watcher", func() { - addActivePods(vmi, pod.UID, "") - - controller.Execute() -- Expect(virtClientset.Actions()).To(HaveLen(1)) -+ -+ Expect(virtClientset.Actions()).To(HaveLen(2)) - Expect(virtClientset.Actions()[0].GetVerb()).To(Equal("create")) - Expect(virtClientset.Actions()[0].GetResource().Resource).To(Equal("virtualmachineinstances")) -+ Expect(virtClientset.Actions()[1].GetVerb()).To(Equal("patch")) -+ Expect(virtClientset.Actions()[1].GetResource().Resource).To(Equal("virtualmachineinstances")) - Expect(kubeClient.Actions()).To(HaveLen(1)) - Expect(kubeClient.Actions()[0].GetVerb()).To(Equal("create")) - Expect(kubeClient.Actions()[0].GetResource().Resource).To(Equal("pods")) -@@ -1662,7 +1672,7 @@ var _ = Describe("VirtualMachineInstance watcher", func() { - Entry("and in pending state", k8sv1.PodPending), - ) - -- It("should add outdated label if pod's image is outdated and VMI is in running state", func() { -+ PIt("should add outdated label if pod's image is outdated and VMI is in running state", func() { - vmi := NewPendingVirtualMachine("testvmi") - setReadyCondition(vmi, k8sv1.ConditionTrue, "") - vmi.Status.Phase = virtv1.Running -@@ -1691,7 +1701,7 @@ var _ = Describe("VirtualMachineInstance watcher", func() { - Expect(updatedPod.Labels).To(HaveKeyWithValue("kubevirt.io/created-by", "1234")) - Expect(updatedPod.Labels).To(HaveKeyWithValue(virtv1.OutdatedLauncherImageLabel, "")) - }) -- It("should remove outdated label if pod's image up-to-date and VMI is in running state", func() { -+ PIt("should remove outdated label if pod's image up-to-date and VMI is in running state", func() { - vmi := NewPendingVirtualMachine("testvmi") - setReadyCondition(vmi, k8sv1.ConditionTrue, "") - vmi.Status.Phase = virtv1.Running -@@ -1721,7 +1731,7 @@ var _ = Describe("VirtualMachineInstance watcher", func() { - Expect(updatedVmi.Labels).To(BeEmpty()) - }) - -- It("should add a ready condition if it is present on the pod and the VMI is in running state", func() { -+ PIt("should add a ready condition if it is present on the pod and the VMI is in running state", func() { - vmi := NewPendingVirtualMachine("testvmi") - vmi.Status.Conditions = nil - vmi.Status.Phase = virtv1.Running -@@ -1742,7 +1752,7 @@ var _ = Describe("VirtualMachineInstance watcher", func() { - )) - }) - -- It("should indicate on the ready condition if the pod is terminating", func() { -+ PIt("should indicate on the ready condition if the pod is terminating", func() { - vmi := NewPendingVirtualMachine("testvmi") - vmi.Status.Conditions = nil - vmi.Status.Phase = virtv1.Running -@@ -1951,7 +1961,7 @@ var _ = Describe("VirtualMachineInstance watcher", func() { - Expect(kubeClient.Actions()).To(HaveLen(2)) // 0: create, 1: get - } - }, -- Entry("when VMI and pod labels differ", -+ PEntry("when VMI and pod labels differ", - &testData{ - vmiLabels: map[string]string{ - virtv1.NodeNameLabel: "node2", -@@ -1967,7 +1977,7 @@ var _ = Describe("VirtualMachineInstance watcher", func() { - expectedPatch: true, - }, - ), -- Entry("when VMI and pod label are the same", -+ PEntry("when VMI and pod label are the same", - &testData{ - vmiLabels: map[string]string{ - virtv1.NodeNameLabel: "node1", -@@ -1983,7 +1993,7 @@ var _ = Describe("VirtualMachineInstance watcher", func() { - expectedPatch: false, - }, - ), -- Entry("when POD label doesn't exist", -+ PEntry("when POD label doesn't exist", - - &testData{ - vmiLabels: map[string]string{ -@@ -1998,7 +2008,7 @@ var _ = Describe("VirtualMachineInstance watcher", func() { - expectedPatch: true, - }, - ), -- Entry("when neither POD or VMI label exists", -+ PEntry("when neither POD or VMI label exists", - &testData{ - vmiLabels: map[string]string{}, - podLabels: map[string]string{}, -@@ -2009,7 +2019,7 @@ var _ = Describe("VirtualMachineInstance watcher", func() { - expectedPatch: false, - }, - ), -- Entry("when POD label exists and VMI does not", -+ PEntry("when POD label exists and VMI does not", - &testData{ - vmiLabels: map[string]string{}, - podLabels: map[string]string{ -@@ -3962,6 +3972,14 @@ func setDataVolumeCondition(dv *cdiv1.DataVolume, cond cdiv1.DataVolumeCondition - dv.Status.Conditions = append(dv.Status.Conditions, cond) - } - -+func NewNodeForPod(pod *k8sv1.Pod) *k8sv1.Node { -+ return &k8sv1.Node{ -+ ObjectMeta: metav1.ObjectMeta{ -+ Name: pod.Spec.NodeName, -+ }, -+ } -+} -+ - func NewPodForVirtualMachine(vmi *virtv1.VirtualMachineInstance, phase k8sv1.PodPhase) *k8sv1.Pod { - podAnnotations := map[string]string{ - virtv1.DomainAnnotation: vmi.Name, -@@ -3978,6 +3996,9 @@ func NewPodForVirtualMachine(vmi *virtv1.VirtualMachineInstance, phase k8sv1.Pod - }, - Annotations: podAnnotations, - }, -+ Spec: k8sv1.PodSpec{ -+ NodeName: "node-01", -+ }, - Status: k8sv1.PodStatus{ - Phase: phase, - ContainerStatuses: []k8sv1.ContainerStatus{ diff --git a/images/virt-artifact/patches/033-manage-pods-network-priotity-during-migration-using-cilium-label.patch b/images/virt-artifact/patches/033-manage-pods-network-priotity-during-migration-using-cilium-label.patch deleted file mode 100644 index 51a6b6bac7..0000000000 --- a/images/virt-artifact/patches/033-manage-pods-network-priotity-during-migration-using-cilium-label.patch +++ /dev/null @@ -1,259 +0,0 @@ -diff --git a/pkg/util/migrations/network.go b/pkg/util/migrations/network.go -new file mode 100644 -index 0000000000..6268e6ea4d ---- /dev/null -+++ b/pkg/util/migrations/network.go -@@ -0,0 +1,64 @@ -+package migrations -+ -+import ( -+ "context" -+ "fmt" -+ -+ v1 "k8s.io/apimachinery/pkg/apis/meta/v1" -+ "k8s.io/apimachinery/pkg/types" -+ virtv1 "kubevirt.io/api/core/v1" -+ "kubevirt.io/client-go/kubecli" -+ -+ "kubevirt.io/kubevirt/pkg/apimachinery/patch" -+) -+ -+type NetworkAccessibilityManager struct { -+ virtClient kubecli.KubevirtClient -+} -+ -+type NetworkPriority = string -+ -+const ( -+ NetworkPriorityTheHighest NetworkPriority = "0" -+ NetworkPriorityDecreased NetworkPriority = "1" -+ NetworkPriorityDeferred NetworkPriority = "2" -+) -+ -+func NewNetworkAccessibilityManager(virtClient kubecli.KubevirtClient) *NetworkAccessibilityManager { -+ return &NetworkAccessibilityManager{ -+ virtClient: virtClient, -+ } -+} -+ -+func (m NetworkAccessibilityManager) SetTheHighestNetworkPriority(ctx context.Context, pod types.NamespacedName) error { -+ patchBytes, err := patch.New( -+ patch.WithTest(fmt.Sprintf("/metadata/labels/%s", patch.EscapeJSONPointer(virtv1.NetworkPriorityLabel)), NetworkPriorityDeferred), -+ patch.WithReplace(fmt.Sprintf("/metadata/labels/%s", patch.EscapeJSONPointer(virtv1.NetworkPriorityLabel)), NetworkPriorityTheHighest), -+ ).GeneratePayload() -+ if err != nil { -+ return fmt.Errorf("generate patch to set new network priority %s=%s for the pod %s: %w", virtv1.NetworkPriorityLabel, NetworkPriorityTheHighest, pod, err) -+ } -+ -+ _, err = m.virtClient.CoreV1().Pods(pod.Namespace).Patch(ctx, pod.Name, types.JSONPatchType, patchBytes, v1.PatchOptions{}) -+ if err != nil { -+ return fmt.Errorf("apply patch to set new network priority %s=%s for the pod %s: %w", virtv1.NetworkPriorityLabel, NetworkPriorityTheHighest, pod, err) -+ } -+ -+ return nil -+} -+ -+func (m NetworkAccessibilityManager) DecreaseNetworkPriority(ctx context.Context, pod types.NamespacedName) error { -+ patchBytes, err := patch.New( -+ patch.WithReplace(fmt.Sprintf("/metadata/labels/%s", patch.EscapeJSONPointer(virtv1.NetworkPriorityLabel)), NetworkPriorityDecreased), -+ ).GeneratePayload() -+ if err != nil { -+ return fmt.Errorf("generate patch to set new network priority %s=%s for the pod %s: %w", virtv1.NetworkPriorityLabel, NetworkPriorityDecreased, pod, err) -+ } -+ -+ _, err = m.virtClient.CoreV1().Pods(pod.Namespace).Patch(ctx, pod.Name, types.JSONPatchType, patchBytes, v1.PatchOptions{}) -+ if err != nil { -+ return fmt.Errorf("apply patch to set new network priority %s=%s for the pod %s: %w", virtv1.NetworkPriorityLabel, NetworkPriorityDecreased, pod, err) -+ } -+ -+ return nil -+} -diff --git a/pkg/virt-controller/watch/migration.go b/pkg/virt-controller/watch/migration.go -index 28d6636b36..4cec8371df 100644 ---- a/pkg/virt-controller/watch/migration.go -+++ b/pkg/virt-controller/watch/migration.go -@@ -115,6 +115,8 @@ type MigrationController struct { - handOffLock sync.Mutex - handOffMap map[string]struct{} - -+ nam *migrations.NetworkAccessibilityManager -+ - unschedulablePendingTimeoutSeconds int64 - catchAllPendingTimeoutSeconds int64 - } -@@ -152,6 +154,8 @@ func NewMigrationController(templateService services.TemplateService, - statusUpdater: status.NewMigrationStatusUpdater(clientset), - handOffMap: make(map[string]struct{}), - -+ nam: migrations.NewNetworkAccessibilityManager(clientset), -+ - unschedulablePendingTimeoutSeconds: defaultUnschedulablePendingTimeoutSeconds, - catchAllPendingTimeoutSeconds: defaultCatchAllPendingTimeoutSeconds, - } -@@ -713,6 +717,9 @@ func (c *MigrationController) createTargetPod(migration *virtv1.VirtualMachineIn - } - } - -+ // Create the new pod with the lowest network priority to prevent Cilium from directing traffic to it. -+ templatePod.Labels[virtv1.NetworkPriorityLabel] = migrations.NetworkPriorityDeferred -+ - key := controller.MigrationKey(migration) - c.podExpectations.ExpectCreations(key, 1) - pod, err := c.clientset.CoreV1().Pods(vmi.GetNamespace()).Create(context.Background(), templatePod, v1.CreateOptions{}) -@@ -1286,6 +1293,18 @@ func (c *MigrationController) sync(key string, migration *virtv1.VirtualMachineI - return nil - } - -+ priority := sourcePod.Labels[virtv1.NetworkPriorityLabel] -+ if priority != migrations.NetworkPriorityDecreased { -+ err = c.nam.DecreaseNetworkPriority(context.Background(), types.NamespacedName{ -+ Namespace: sourcePod.Namespace, -+ Name: sourcePod.Name, -+ }) -+ if err != nil { -+ log.Log.Reason(err).Error("Failed to decrease the network priority for the source pod, please report a bug") -+ return fmt.Errorf("decrease network priority: %w", err) -+ } -+ } -+ - if _, exists := migration.GetAnnotations()[virtv1.EvacuationMigrationAnnotation]; exists { - if err = descheduler.MarkEvictionInProgress(c.clientset, sourcePod); err != nil { - return err -diff --git a/pkg/virt-handler/vm.go b/pkg/virt-handler/vm.go -index 301d7b2249..ce689368a8 100644 ---- a/pkg/virt-handler/vm.go -+++ b/pkg/virt-handler/vm.go -@@ -255,6 +255,7 @@ func NewController( - clusterConfig, - hotplugdisk.NewHotplugDiskManager(kubeletPodsDir), - ), -+ nam: migrations.NewNetworkAccessibilityManager(clientset), - } - - _, err := vmiSourceInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{ -@@ -284,6 +285,13 @@ func NewController( - return nil, err - } - -+ _, err = domainInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{ -+ UpdateFunc: c.updateNetworkPriorityFunc, -+ }) -+ if err != nil { -+ return nil, err -+ } -+ - c.launcherClients = virtcache.LauncherClientInfoByVMI{} - - c.netConf = netsetup.NewNetConf() -@@ -352,6 +360,7 @@ type VirtualMachineController struct { - ioErrorRetryManager *FailRetryManager - - hotplugContainerDiskMounter container_disk.HotplugMounter -+ nam *migrations.NetworkAccessibilityManager - } - - type virtLauncherCriticalSecurebootError struct { -@@ -3809,3 +3818,43 @@ func (d *VirtualMachineController) updateMemoryInfo(vmi *v1.VirtualMachineInstan - vmi.Status.Memory.GuestCurrent = currentGuest - return nil - } -+ -+func (d *VirtualMachineController) updateNetworkPriorityFunc(_, new interface{}) { -+ newDomain := new.(*api.Domain) -+ -+ _, ok := newDomain.Annotations[v1.VirtualMachineSuspendedMigratedAnnotation] -+ if !ok { -+ return -+ } -+ -+ key, err := controller.KeyFunc(new) -+ if err != nil { -+ log.Log.Object(newDomain).Reason(err).Error("Failed to call key func: cannot update network priority") -+ return -+ } -+ -+ vmi, _, err := d.getVMIFromCache(key) -+ if err != nil { -+ log.Log.Object(newDomain).Reason(err).With("key", key).Errorf("Failed to get vmi from cache: cannot update network priority") -+ return -+ } -+ -+ if vmi == nil { -+ log.Log.Object(newDomain).With("key", key).Error("Got nil vmi: cannot update network priority") -+ return -+ } -+ -+ if vmi.Status.MigrationState == nil || vmi.Status.MigrationState.TargetPod == "" { -+ log.Log.Object(newDomain).With("key", key).Error("Cannot determine target pod name: cannot update network priority") -+ return -+ } -+ -+ err = d.nam.SetTheHighestNetworkPriority(context.Background(), types.NamespacedName{ -+ Namespace: vmi.Namespace, -+ Name: vmi.Status.MigrationState.TargetPod, -+ }) -+ if err != nil { -+ log.Log.Object(newDomain).Reason(err).With("key", key).Error("Failed to set network priority high for the target pod") -+ return -+ } -+} -diff --git a/pkg/virt-launcher/notify-client/client.go b/pkg/virt-launcher/notify-client/client.go -index bb63f2eac5..5da5f68103 100644 ---- a/pkg/virt-launcher/notify-client/client.go -+++ b/pkg/virt-launcher/notify-client/client.go -@@ -352,6 +352,14 @@ func eventCallback(c cli.Connection, domain *api.Domain, libvirtEvent libvirtEve - domain.Status.FSFreezeStatus = *fsFreezeStatus - } - -+ if libvirtEvent.Event != nil && libvirtEvent.Event.Event == libvirt.DOMAIN_EVENT_SUSPENDED && libvirtEvent.Event.Detail == int(libvirt.DOMAIN_EVENT_SUSPENDED_MIGRATED) { -+ if domain.Annotations == nil { -+ domain.Annotations = make(map[string]string) -+ } -+ -+ domain.Annotations[v1.VirtualMachineSuspendedMigratedAnnotation] = "" -+ } -+ - err := client.SendDomainEvent(watch.Event{Type: watch.Modified, Object: domain}) - if err != nil { - log.Log.Reason(err).Error("Could not send domain notify event.") -diff --git a/pkg/virt-operator/resource/generate/rbac/handler.go b/pkg/virt-operator/resource/generate/rbac/handler.go -index e55a4044ea..2640f61826 100644 ---- a/pkg/virt-operator/resource/generate/rbac/handler.go -+++ b/pkg/virt-operator/resource/generate/rbac/handler.go -@@ -156,6 +156,17 @@ func newHandlerClusterRole() *rbacv1.ClusterRole { - "get", "list", "watch", - }, - }, -+ { -+ APIGroups: []string{ -+ "", -+ }, -+ Resources: []string{ -+ "pods", -+ }, -+ Verbs: []string{ -+ "patch", -+ }, -+ }, - }, - } - } -diff --git a/staging/src/kubevirt.io/api/core/v1/types.go b/staging/src/kubevirt.io/api/core/v1/types.go -index 841387d304..403a28610e 100644 ---- a/staging/src/kubevirt.io/api/core/v1/types.go -+++ b/staging/src/kubevirt.io/api/core/v1/types.go -@@ -878,6 +878,14 @@ const ( - // Machine Instance migration job. Needed because with CRDs we can't use field - // selectors. Used on VirtualMachineInstance. - MigrationTargetNodeNameLabel string = "kubevirt.io/migrationTargetNodeName" -+ // A special label allows setting the priority of pod for cilium relative to other pods with the same IP address. -+ // Network traffic will be directed to the pod with the higher priority. -+ // Absence of the label means the lowest priority (pod with a network priority label is more prioritized than a pod without a label). -+ // The lower the numerical value, the higher the priority. -+ NetworkPriorityLabel string = "network.deckhouse.io/pod-common-ip-priority" -+ // A special annotation through which information is passed from virt-launcher to virt-handler indicating -+ // that the virtual machine has been suspended for offline migration. -+ VirtualMachineSuspendedMigratedAnnotation string = "kubevirt.io/vm-suspended-migrated" - // This annotation indicates that a migration is the result of an - // automated evacuation - EvacuationMigrationAnnotation string = "kubevirt.io/evacuationMigration" diff --git a/images/virt-artifact/patches/034-allow-update-kvvmi-for-virtualization-sas.patch b/images/virt-artifact/patches/034-allow-update-kvvmi-for-virtualization-sas.patch deleted file mode 100644 index 91f5ad26c8..0000000000 --- a/images/virt-artifact/patches/034-allow-update-kvvmi-for-virtualization-sas.patch +++ /dev/null @@ -1,27 +0,0 @@ -diff --git a/pkg/virt-api/webhooks/utils.go b/pkg/virt-api/webhooks/utils.go -index e6ee54431f..5c68ce992d 100644 ---- a/pkg/virt-api/webhooks/utils.go -+++ b/pkg/virt-api/webhooks/utils.go -@@ -100,7 +100,9 @@ func IsKubeVirtServiceAccount(serviceAccount string) bool { - - return IsComponentServiceAccount(serviceAccount, ns, components.ApiServiceAccountName) || - IsComponentServiceAccount(serviceAccount, ns, components.HandlerServiceAccountName) || -- IsComponentServiceAccount(serviceAccount, ns, components.ControllerServiceAccountName) -+ IsComponentServiceAccount(serviceAccount, ns, components.ControllerServiceAccountName) || -+ IsComponentServiceAccount(serviceAccount, ns, components.VirtualizationController) || -+ IsComponentServiceAccount(serviceAccount, ns, components.VirtualizationApi) - } - - func IsARM64(vmiSpec *v1.VirtualMachineInstanceSpec) bool { -diff --git a/pkg/virt-operator/resource/generate/components/serviceaccountnames.go b/pkg/virt-operator/resource/generate/components/serviceaccountnames.go -index 9aca3b3bd2..4ed51d98b5 100644 ---- a/pkg/virt-operator/resource/generate/components/serviceaccountnames.go -+++ b/pkg/virt-operator/resource/generate/components/serviceaccountnames.go -@@ -6,4 +6,7 @@ const ( - ExportProxyServiceAccountName = "kubevirt-internal-virtualization-exportproxy" - HandlerServiceAccountName = "kubevirt-internal-virtualization-handler" - OperatorServiceAccountName = "kubevirt-operator" -+ -+ VirtualizationController = "virtualization-controller" -+ VirtualizationApi = "virtualization-api" - ) diff --git a/images/virt-artifact/patches/035-allow-change-serial-on-kvvmi.patch b/images/virt-artifact/patches/035-allow-change-serial-on-kvvmi.patch deleted file mode 100644 index 41808680dd..0000000000 --- a/images/virt-artifact/patches/035-allow-change-serial-on-kvvmi.patch +++ /dev/null @@ -1,49 +0,0 @@ -diff --git a/pkg/virt-api/webhooks/validating-webhook/admitters/util.go b/pkg/virt-api/webhooks/validating-webhook/admitters/util.go -new file mode 100644 -index 0000000000..6d0699b12d ---- /dev/null -+++ b/pkg/virt-api/webhooks/validating-webhook/admitters/util.go -@@ -0,0 +1,19 @@ -+package admitters -+ -+import ( -+ "k8s.io/apimachinery/pkg/api/equality" -+ v1 "kubevirt.io/api/core/v1" -+) -+ -+func equalDiskIgnoreSerial(newDisk, oldDisk v1.Disk) bool { -+ return equality.Semantic.DeepEqual(newDisk.Name, oldDisk.Name) && -+ equality.Semantic.DeepEqual(newDisk.DiskDevice, oldDisk.DiskDevice) && -+ equality.Semantic.DeepEqual(newDisk.BootOrder, oldDisk.BootOrder) && -+ equality.Semantic.DeepEqual(newDisk.DedicatedIOThread, oldDisk.DedicatedIOThread) && -+ equality.Semantic.DeepEqual(newDisk.Cache, oldDisk.Cache) && -+ equality.Semantic.DeepEqual(newDisk.IO, oldDisk.IO) && -+ equality.Semantic.DeepEqual(newDisk.Tag, oldDisk.Tag) && -+ equality.Semantic.DeepEqual(newDisk.BlockSize, oldDisk.BlockSize) && -+ equality.Semantic.DeepEqual(newDisk.Shareable, oldDisk.Shareable) && -+ equality.Semantic.DeepEqual(newDisk.ErrorPolicy, oldDisk.ErrorPolicy) -+} -diff --git a/pkg/virt-api/webhooks/validating-webhook/admitters/vmi-update-admitter.go b/pkg/virt-api/webhooks/validating-webhook/admitters/vmi-update-admitter.go -index b984ff4262..8201d9375b 100644 ---- a/pkg/virt-api/webhooks/validating-webhook/admitters/vmi-update-admitter.go -+++ b/pkg/virt-api/webhooks/validating-webhook/admitters/vmi-update-admitter.go -@@ -189,7 +189,8 @@ func verifyHotplugVolumes(newHotplugVolumeMap, oldHotplugVolumeMap map[string]v1 - }, - }) - } -- if !equality.Semantic.DeepEqual(newDisks[k], oldDisks[k]) { -+ -+ if !equalDiskIgnoreSerial(newDisks[k], oldDisks[k]) { - return webhookutils.ToAdmissionResponse([]metav1.StatusCause{ - { - Type: metav1.CauseTypeFieldValueInvalid, -@@ -292,7 +293,8 @@ func verifyPermanentVolumes(newPermanentVolumeMap, oldPermanentVolumeMap map[str - }, - }) - } -- if !equality.Semantic.DeepEqual(newDisks[k], oldDisks[k]) { -+ -+ if !equalDiskIgnoreSerial(newDisks[k], oldDisks[k]) { - return webhookutils.ToAdmissionResponse([]metav1.StatusCause{ - { - Type: metav1.CauseTypeFieldValueInvalid, diff --git a/images/virt-artifact/patches/036-enhance-SCSI-disk-serial-validation.patch b/images/virt-artifact/patches/036-enhance-SCSI-disk-serial-validation.patch deleted file mode 100644 index 30d8bd0a8d..0000000000 --- a/images/virt-artifact/patches/036-enhance-SCSI-disk-serial-validation.patch +++ /dev/null @@ -1,123 +0,0 @@ -diff --git a/pkg/util/hardware/hw_utils.go b/pkg/util/hardware/hw_utils.go -index a3bb25c3ab..cb38f3667a 100644 ---- a/pkg/util/hardware/hw_utils.go -+++ b/pkg/util/hardware/hw_utils.go -@@ -35,6 +35,7 @@ import ( - - const ( - PCI_ADDRESS_PATTERN = `^([\da-fA-F]{4}):([\da-fA-F]{2}):([\da-fA-F]{2})\.([0-7]{1})$` -+ MaxSCSISerialLen = 36 - ) - - // Parse linux cpuset into an array of ints -@@ -178,3 +179,10 @@ func LookupDeviceVCPUAffinity(pciAddress string, domainSpec *api.DomainSpec) ([] - } - return alignedVCPUList, nil - } -+ -+func TruncateSCSIDiskSerial(serial string) string { -+ if len(serial) <= MaxSCSISerialLen { -+ return serial -+ } -+ return string([]byte(serial)[:MaxSCSISerialLen]) -+} -diff --git a/pkg/virt-api/webhooks/mutating-webhook/mutators/vmi-mutator.go b/pkg/virt-api/webhooks/mutating-webhook/mutators/vmi-mutator.go -index 2747d6b7ea..65a861b3fe 100644 ---- a/pkg/virt-api/webhooks/mutating-webhook/mutators/vmi-mutator.go -+++ b/pkg/virt-api/webhooks/mutating-webhook/mutators/vmi-mutator.go -@@ -36,6 +36,7 @@ import ( - "kubevirt.io/kubevirt/pkg/apimachinery/patch" - kvpointer "kubevirt.io/kubevirt/pkg/pointer" - "kubevirt.io/kubevirt/pkg/util" -+ hwutil "kubevirt.io/kubevirt/pkg/util/hardware" - webhookutils "kubevirt.io/kubevirt/pkg/util/webhooks" - "kubevirt.io/kubevirt/pkg/virt-api/webhooks" - virtconfig "kubevirt.io/kubevirt/pkg/virt-config" -@@ -98,6 +99,22 @@ func (mutator *VMIsMutator) Mutate(ar *admissionv1.AdmissionReview) *admissionv1 - addNodeSelector(newVMI, v1.SEVESLabel) - } - -+ // To maintain backward compatibility, a mutation webhook was added. -+ // This ensures that if a VMI is created by another controller within KubeVirt (instead of a user), the serial number is automatically truncated to MaxSCSISerialLen. -+ // This prevents issues where an existing VM with an invalid serial length would fail validation when starting a VMI. -+ // Without this, such a VM could break due to the validation webhook rejecting the creation of VMI, effectively blocking its startup. -+ for _, ref := range newVMI.OwnerReferences { -+ if ref.APIVersion == v1.SchemeGroupVersion.String() { -+ for i := range newVMI.Spec.Domain.Devices.Disks { -+ d := &newVMI.Spec.Domain.Devices.Disks[i] -+ if d.Disk != nil && d.Disk.Bus == v1.DiskBusSCSI { -+ d.Serial = hwutil.TruncateSCSIDiskSerial(d.Serial) -+ } -+ } -+ break -+ } -+ } -+ - if newVMI.Spec.Domain.CPU.IsolateEmulatorThread { - _, emulatorThreadCompleteToEvenParityAnnotationExists := mutator.ClusterConfig.GetConfigFromKubeVirtCR().Annotations[v1.EmulatorThreadCompleteToEvenParity] - if emulatorThreadCompleteToEvenParityAnnotationExists && -diff --git a/pkg/virt-api/webhooks/validating-webhook/admitters/vmi-create-admitter.go b/pkg/virt-api/webhooks/validating-webhook/admitters/vmi-create-admitter.go -index edcdd358bb..b008cd40ae 100644 ---- a/pkg/virt-api/webhooks/validating-webhook/admitters/vmi-create-admitter.go -+++ b/pkg/virt-api/webhooks/validating-webhook/admitters/vmi-create-admitter.go -@@ -2034,13 +2034,22 @@ func validateSerialNumValue(field *k8sfield.Path, idx int, disk v1.Disk) []metav - - func validateSerialNumLength(field *k8sfield.Path, idx int, disk v1.Disk) []metav1.StatusCause { - var causes []metav1.StatusCause -- if disk.Serial != "" && len([]rune(disk.Serial)) > maxStrLen { -+ -+ if disk.Disk != nil && disk.Disk.Bus == v1.DiskBusSCSI && len(disk.Serial) > hwutil.MaxSCSISerialLen { - causes = append(causes, metav1.StatusCause{ - Type: metav1.CauseTypeFieldValueInvalid, -- Message: fmt.Sprintf("%s must be less than or equal to %d in length, if specified", field.Index(idx).String(), maxStrLen), -+ Message: fmt.Sprintf("SCSI device serial should not be more than %d symbols. Got %d (%s) for disk %s", hwutil.MaxSCSISerialLen, len(disk.Serial), disk.Serial, field.Index(idx).String()), -+ Field: field.Index(idx).Child("serial").String(), -+ }) -+ -+ } else if len(disk.Serial) > maxStrLen { -+ causes = append(causes, metav1.StatusCause{ -+ Type: metav1.CauseTypeFieldValueInvalid, -+ Message: fmt.Sprintf("disk serial should not be more than %d symbols. Got %d (%s) for disk %s.", maxStrLen, len(disk.Serial), disk.Serial, field.Index(idx).String()), - Field: field.Index(idx).Child("serial").String(), - }) - } -+ - return causes - } - -diff --git a/pkg/virt-launcher/virtwrap/converter/converter.go b/pkg/virt-launcher/virtwrap/converter/converter.go -index 393415c36c..cc09800afc 100644 ---- a/pkg/virt-launcher/virtwrap/converter/converter.go -+++ b/pkg/virt-launcher/virtwrap/converter/converter.go -@@ -37,6 +37,7 @@ import ( - "syscall" - - "kubevirt.io/kubevirt/pkg/storage/reservation" -+ hwutil "kubevirt.io/kubevirt/pkg/util/hardware" - "kubevirt.io/kubevirt/pkg/virt-controller/watch/topology" - - "golang.org/x/sys/unix" -@@ -168,10 +169,15 @@ func Convert_v1_Disk_To_api_Disk(c *ConverterContext, diskDevice *v1.Disk, disk - if diskDevice.Disk != nil { - var unit int - disk.Device = "disk" -+ disk.Serial = diskDevice.Serial - disk.Target.Bus = diskDevice.Disk.Bus - disk.Target.Device, unit = makeDeviceName(diskDevice.Name, diskDevice.Disk.Bus, prefixMap) - if diskDevice.Disk.Bus == "scsi" { - assignDiskToSCSIController(disk, unit) -+ // Force truncation of serial number to MaxSCSISerialLen characters, as QEMU no longer does this automatically. -+ // This is required to maintain backward compatibility. Specifying devices with serial numbers longer than MaxSCSISerialLen -+ // characters is not allowed now. -+ disk.Serial = hwutil.TruncateSCSIDiskSerial(diskDevice.Serial) - } - if diskDevice.Disk.PciAddress != "" { - if diskDevice.Disk.Bus != v1.DiskBusVirtio { -@@ -187,7 +193,6 @@ func Convert_v1_Disk_To_api_Disk(c *ConverterContext, diskDevice *v1.Disk, disk - disk.Model = InterpretTransitionalModelType(&c.UseVirtioTransitional, c.Architecture) - } - disk.ReadOnly = toApiReadOnly(diskDevice.Disk.ReadOnly) -- disk.Serial = diskDevice.Serial - if diskDevice.Shareable != nil { - if *diskDevice.Shareable { - if diskDevice.Cache == "" { diff --git a/images/virt-artifact/patches/037-set-ReadOnlyRootFilesystem-to-virt-launcher.patch b/images/virt-artifact/patches/037-set-ReadOnlyRootFilesystem-to-virt-launcher.patch deleted file mode 100644 index 4f6eeee8fe..0000000000 --- a/images/virt-artifact/patches/037-set-ReadOnlyRootFilesystem-to-virt-launcher.patch +++ /dev/null @@ -1,352 +0,0 @@ -diff --git a/pkg/virt-controller/services/rendervolumes.go b/pkg/virt-controller/services/rendervolumes.go -index de90ed3cbc..992a449bcc 100644 ---- a/pkg/virt-controller/services/rendervolumes.go -+++ b/pkg/virt-controller/services/rendervolumes.go -@@ -52,6 +52,13 @@ func NewVolumeRenderer(namespace string, ephemeralDisk string, containerDiskDir - - func (vr *VolumeRenderer) Mounts() []k8sv1.VolumeMount { - volumeMounts := []k8sv1.VolumeMount{ -+ mountPath(varRunVolumeName, varRun), -+ mountPath(varLogVolumeName, varLog), -+ mountPath(etcLibvirtVolumeName, etcLibvirt), -+ mountPath(varLibLibvirtVolumeName, varLibLibvirt), -+ mountPath(varCacheLibvirtVolumeName, varCacheLibvirt), -+ mountPath(tmpVolumeName, tmp), -+ mountPath(varLibSWTPMLocalCAVolumeName, varLibSWTPMLocalCA), - mountPath("private", util.VirtPrivateDir), - mountPath("public", util.VirtShareDir), - mountPath("ephemeral-disks", vr.ephemeralDiskDir), -@@ -64,6 +71,13 @@ func (vr *VolumeRenderer) Mounts() []k8sv1.VolumeMount { - - func (vr *VolumeRenderer) Volumes() []k8sv1.Volume { - volumes := []k8sv1.Volume{ -+ emptyDirVolume(varRunVolumeName), -+ emptyDirVolume(varLogVolumeName), -+ emptyDirVolume(etcLibvirtVolumeName), -+ emptyDirVolume(varLibLibvirtVolumeName), -+ emptyDirVolume(varCacheLibvirtVolumeName), -+ emptyDirVolume(tmpVolumeName), -+ emptyDirVolume(varLibSWTPMLocalCAVolumeName), - emptyDirVolume("private"), - emptyDirVolume("public"), - emptyDirVolume("sockets"), -diff --git a/pkg/virt-controller/services/rendervolumes_test.go b/pkg/virt-controller/services/rendervolumes_test.go -index e112967eec..4781a313d7 100644 ---- a/pkg/virt-controller/services/rendervolumes_test.go -+++ b/pkg/virt-controller/services/rendervolumes_test.go -@@ -342,6 +342,34 @@ func vmiDiskPath(volumeName string) string { - - func defaultVolumes() []k8sv1.Volume { - return []k8sv1.Volume{ -+ { -+ Name: varRunVolumeName, -+ VolumeSource: k8sv1.VolumeSource{EmptyDir: &k8sv1.EmptyDirVolumeSource{}}, -+ }, -+ { -+ Name: varLogVolumeName, -+ VolumeSource: k8sv1.VolumeSource{EmptyDir: &k8sv1.EmptyDirVolumeSource{}}, -+ }, -+ { -+ Name: etcLibvirtVolumeName, -+ VolumeSource: k8sv1.VolumeSource{EmptyDir: &k8sv1.EmptyDirVolumeSource{}}, -+ }, -+ { -+ Name: varLibLibvirtVolumeName, -+ VolumeSource: k8sv1.VolumeSource{EmptyDir: &k8sv1.EmptyDirVolumeSource{}}, -+ }, -+ { -+ Name: varCacheLibvirtVolumeName, -+ VolumeSource: k8sv1.VolumeSource{EmptyDir: &k8sv1.EmptyDirVolumeSource{}}, -+ }, -+ { -+ Name: tmpVolumeName, -+ VolumeSource: k8sv1.VolumeSource{EmptyDir: &k8sv1.EmptyDirVolumeSource{}}, -+ }, -+ { -+ Name: varLibSWTPMLocalCAVolumeName, -+ VolumeSource: k8sv1.VolumeSource{EmptyDir: &k8sv1.EmptyDirVolumeSource{}}, -+ }, - { - Name: "private", - VolumeSource: k8sv1.VolumeSource{EmptyDir: &k8sv1.EmptyDirVolumeSource{}}, -@@ -371,6 +399,13 @@ func defaultVolumeMounts() []k8sv1.VolumeMount { - hostToContainerPropagation := k8sv1.MountPropagationHostToContainer - - return []k8sv1.VolumeMount{ -+ {Name: varRunVolumeName, MountPath: varRun}, -+ {Name: varLogVolumeName, MountPath: varLog}, -+ {Name: etcLibvirtVolumeName, MountPath: etcLibvirt}, -+ {Name: varLibLibvirtVolumeName, MountPath: varLibLibvirt}, -+ {Name: varCacheLibvirtVolumeName, MountPath: varCacheLibvirt}, -+ {Name: tmpVolumeName, MountPath: tmp}, -+ {Name: varLibSWTPMLocalCAVolumeName, MountPath: varLibSWTPMLocalCA}, - {Name: "private", MountPath: "/var/run/kubevirt-private"}, - {Name: "public", MountPath: "/var/run/kubevirt"}, - {Name: "ephemeral-disks", MountPath: "disk1"}, -diff --git a/pkg/virt-controller/services/template.go b/pkg/virt-controller/services/template.go -index f607c24786..1221448946 100644 ---- a/pkg/virt-controller/services/template.go -+++ b/pkg/virt-controller/services/template.go -@@ -64,15 +64,28 @@ import ( - ) - - const ( -- containerDisks = "container-disks" -- hotplugDisks = "hotplug-disks" -- hookSidecarSocks = "hook-sidecar-sockets" -- varRun = "/var/run" -- virtBinDir = "virt-bin-share-dir" -- hotplugDisk = "hotplug-disk" -- virtExporter = "virt-exporter" -- hotplugContainerDisks = "hotplug-container-disks" -- HotplugContainerDisk = "hotplug-container-disk-" -+ containerDisks = "container-disks" -+ hotplugDisks = "hotplug-disks" -+ hookSidecarSocks = "hook-sidecar-sockets" -+ varRun = "/var/run" -+ virtBinDir = "virt-bin-share-dir" -+ hotplugDisk = "hotplug-disk" -+ virtExporter = "virt-exporter" -+ hotplugContainerDisks = "hotplug-container-disks" -+ HotplugContainerDisk = "hotplug-container-disk-" -+ varLog = "/var/log" -+ etcLibvirt = "/etc/libvirt" -+ varLibLibvirt = "/var/lib/libvirt" -+ varCacheLibvirt = "/var/cache/libvirt" -+ tmp = "/tmp" -+ varLibSWTPMLocalCA = "/var/lib/swtpm-localca" -+ varLogVolumeName = "var-log" -+ etcLibvirtVolumeName = "etc-libvirt" -+ varLibLibvirtVolumeName = "var-lib-libvirt" -+ varCacheLibvirtVolumeName = "var-cache-libvirt" -+ varRunVolumeName = "var-run" -+ tmpVolumeName = "tmp" -+ varLibSWTPMLocalCAVolumeName = "var-lib-swtpm-localca" - ) - - const KvmDevice = "devices.virtualization.deckhouse.io/kvm" -@@ -301,7 +314,6 @@ func generateQemuTimeoutWithJitter(qemuTimeoutBaseSeconds int) string { - - func computePodSecurityContext(vmi *v1.VirtualMachineInstance, seccomp *k8sv1.SeccompProfile) *k8sv1.PodSecurityContext { - psc := &k8sv1.PodSecurityContext{} -- - if util.IsNonRootVMI(vmi) { - nonRootUser := int64(util.NonRootUID) - psc.RunAsUser = &nonRootUser -@@ -573,6 +585,20 @@ func (t *templateService) renderLaunchManifest(vmi *v1.VirtualMachineInstance, i - } - - } -+ -+ // Set ReadOnlyRootFilesystem -+ setReadOnlyRootFilesystem := func(ctrs []k8sv1.Container) { -+ for i := range ctrs { -+ ctr := &ctrs[i] -+ if ctr.SecurityContext == nil { -+ ctr.SecurityContext = &k8sv1.SecurityContext{} -+ } -+ ctr.SecurityContext.ReadOnlyRootFilesystem = pointer.Bool(true) -+ } -+ } -+ setReadOnlyRootFilesystem(initContainers) -+ setReadOnlyRootFilesystem(containers) -+ - pod := k8sv1.Pod{ - ObjectMeta: metav1.ObjectMeta{ - GenerateName: "virt-launcher-" + domain + "-", -diff --git a/pkg/virt-controller/services/template_test.go b/pkg/virt-controller/services/template_test.go -index c6a7f66a54..80dab4e808 100644 ---- a/pkg/virt-controller/services/template_test.go -+++ b/pkg/virt-controller/services/template_test.go -@@ -458,7 +458,7 @@ var _ = Describe("Template", func() { - Expect(pod.Spec.Containers[1].Image).To(Equal("some-image:v1")) - Expect(pod.Spec.Containers[1].ImagePullPolicy).To(Equal(k8sv1.PullPolicy("IfNotPresent"))) - Expect(*pod.Spec.TerminationGracePeriodSeconds).To(Equal(int64(60))) -- Expect(pod.Spec.InitContainers).To(BeEmpty()) -+ Expect(pod.Spec.InitContainers).To(HaveLen(0)) - By("setting the right hostname") - Expect(pod.Spec.Hostname).To(Equal("testvmi")) - Expect(pod.Spec.Subdomain).To(BeEmpty()) -@@ -2314,7 +2314,7 @@ var _ = Describe("Template", func() { - Expect(hugepagesRequest.ToDec().ScaledValue(resource.Mega)).To(Equal(int64(64))) - Expect(hugepagesLimit.ToDec().ScaledValue(resource.Mega)).To(Equal(int64(64))) - -- Expect(pod.Spec.Volumes).To(HaveLen(9)) -+ Expect(pod.Spec.Volumes).To(HaveLen(16)) - Expect(pod.Spec.Volumes).To( - ContainElements( - k8sv1.Volume{ -@@ -2329,7 +2329,7 @@ var _ = Describe("Template", func() { - EmptyDir: &k8sv1.EmptyDirVolumeSource{}, - }})) - -- Expect(pod.Spec.Containers[0].VolumeMounts).To(HaveLen(8)) -+ Expect(pod.Spec.Containers[0].VolumeMounts).To(HaveLen(15)) - Expect(pod.Spec.Containers[0].VolumeMounts).To( - ContainElements( - k8sv1.VolumeMount{ -@@ -2393,7 +2393,7 @@ var _ = Describe("Template", func() { - Expect(hugepagesRequest.ToDec().ScaledValue(resource.Mega)).To(Equal(int64(64))) - Expect(hugepagesLimit.ToDec().ScaledValue(resource.Mega)).To(Equal(int64(64))) - -- Expect(pod.Spec.Volumes).To(HaveLen(9)) -+ Expect(pod.Spec.Volumes).To(HaveLen(16)) - Expect(pod.Spec.Volumes).To( - ContainElements( - k8sv1.Volume{ -@@ -2408,7 +2408,7 @@ var _ = Describe("Template", func() { - EmptyDir: &k8sv1.EmptyDirVolumeSource{}, - }})) - -- Expect(pod.Spec.Containers[0].VolumeMounts).To(HaveLen(8)) -+ Expect(pod.Spec.Containers[0].VolumeMounts).To(HaveLen(15)) - Expect(pod.Spec.Containers[0].VolumeMounts).To( - ContainElements( - k8sv1.VolumeMount{ -@@ -2463,11 +2463,11 @@ var _ = Describe("Template", func() { - Expect(pod.Spec.Containers[0].VolumeDevices).To(BeEmpty(), "No devices in manifest for 1st container") - - Expect(pod.Spec.Containers[0].VolumeMounts).ToNot(BeEmpty(), "Some mounts in manifest for 1st container") -- Expect(pod.Spec.Containers[0].VolumeMounts).To(HaveLen(7), "7 mounts in manifest for 1st container") -- Expect(pod.Spec.Containers[0].VolumeMounts[6].Name).To(Equal(volumeName), "1st mount in manifest for 1st container has correct name") -+ Expect(pod.Spec.Containers[0].VolumeMounts).To(HaveLen(14), "14 mounts in manifest for 1st container") -+ Expect(pod.Spec.Containers[0].VolumeMounts[13].Name).To(Equal(volumeName), "1st mount in manifest for 1st container has correct name") - - Expect(pod.Spec.Volumes).ToNot(BeEmpty(), "Found some volumes in manifest") -- Expect(pod.Spec.Volumes).To(HaveLen(8), "Found 8 volumes in manifest") -+ Expect(pod.Spec.Volumes).To(HaveLen(15), "Found 15 volumes in manifest") - Expect(pod.Spec.Volumes).To( - ContainElement( - k8sv1.Volume{ -@@ -2535,10 +2535,10 @@ var _ = Describe("Template", func() { - Expect(pod.Spec.Containers[0].VolumeDevices[1].Name).To(Equal(ephemeralVolumeName), "Found device for 1st container with correct name") - - Expect(pod.Spec.Containers[0].VolumeMounts).ToNot(BeEmpty(), "Found some mounts in manifest for 1st container") -- Expect(pod.Spec.Containers[0].VolumeMounts).To(HaveLen(6), "Found 6 mounts in manifest for 1st container") -+ Expect(pod.Spec.Containers[0].VolumeMounts).To(HaveLen(13), "Found 13 mounts in manifest for 1st container") - - Expect(pod.Spec.Volumes).ToNot(BeEmpty(), "Found some volumes in manifest") -- Expect(pod.Spec.Volumes).To(HaveLen(9), "Found 9 volumes in manifest") -+ Expect(pod.Spec.Volumes).To(HaveLen(16), "Found 16 volumes in manifest") - Expect(pod.Spec.Volumes).To( - ContainElement( - k8sv1.Volume{ -@@ -3048,7 +3048,7 @@ var _ = Describe("Template", func() { - pod, err := svc.RenderLaunchManifest(vmi) - Expect(err).ToNot(HaveOccurred()) - Expect(pod.Spec.Volumes).ToNot(BeEmpty()) -- Expect(pod.Spec.Volumes).To(HaveLen(8)) -+ Expect(pod.Spec.Volumes).To(HaveLen(15)) - - oneMB := resource.MustParse("1Mi") - Expect(pod.Spec.Volumes).To(ContainElement( -@@ -3062,7 +3062,7 @@ var _ = Describe("Template", func() { - }, - })) - -- Expect(pod.Spec.Containers[0].VolumeMounts[6].MountPath).To(Equal(k6tconfig.DownwardMetricDisksDir)) -+ Expect(pod.Spec.Containers[0].VolumeMounts[13].MountPath).To(Equal(k6tconfig.DownwardMetricDisksDir)) - }) - - It("Should add 1Mi memory overhead", func() { -@@ -3116,7 +3116,7 @@ var _ = Describe("Template", func() { - Expect(err).ToNot(HaveOccurred()) - - Expect(pod.Spec.Volumes).ToNot(BeEmpty()) -- Expect(pod.Spec.Volumes).To(HaveLen(8)) -+ Expect(pod.Spec.Volumes).To(HaveLen(15)) - Expect(pod.Spec.Volumes).To(ContainElement(k8sv1.Volume{ - Name: "configmap-volume", - VolumeSource: k8sv1.VolumeSource{ -@@ -3155,7 +3155,7 @@ var _ = Describe("Template", func() { - Expect(err).ToNot(HaveOccurred()) - - Expect(pod.Spec.Volumes).ToNot(BeEmpty()) -- Expect(pod.Spec.Volumes).To(HaveLen(9)) -+ Expect(pod.Spec.Volumes).To(HaveLen(16)) - Expect(pod.Spec.Volumes).To(ContainElement(k8sv1.Volume{ - Name: "sysprep-configmap-volume", - VolumeSource: k8sv1.VolumeSource{ -@@ -3192,7 +3192,7 @@ var _ = Describe("Template", func() { - Expect(err).ToNot(HaveOccurred()) - - Expect(pod.Spec.Volumes).ToNot(BeEmpty()) -- Expect(pod.Spec.Volumes).To(HaveLen(9)) -+ Expect(pod.Spec.Volumes).To(HaveLen(16)) - - Expect(pod.Spec.Volumes).To(ContainElement(k8sv1.Volume{ - Name: "sysprep-configmap-volume", -@@ -3234,7 +3234,7 @@ var _ = Describe("Template", func() { - Expect(err).ToNot(HaveOccurred()) - - Expect(pod.Spec.Volumes).ToNot(BeEmpty()) -- Expect(pod.Spec.Volumes).To(HaveLen(8)) -+ Expect(pod.Spec.Volumes).To(HaveLen(15)) - - Expect(pod.Spec.Volumes).To(ContainElement(k8sv1.Volume{ - Name: "secret-volume", -diff --git a/pkg/virt-launcher/virtwrap/util/libvirt_helper.go b/pkg/virt-launcher/virtwrap/util/libvirt_helper.go -index b342c034f7..37630f597f 100644 ---- a/pkg/virt-launcher/virtwrap/util/libvirt_helper.go -+++ b/pkg/virt-launcher/virtwrap/util/libvirt_helper.go -@@ -472,7 +472,60 @@ func copyFile(from, to string) error { - return err - } - -+func copyDir(src, dest string) error { -+ sourceDirInfo, err := os.Stat(src) -+ if err != nil { -+ return err -+ } -+ -+ if _, err = os.Stat(dest); err != nil { -+ if os.IsNotExist(err) { -+ err = os.MkdirAll(dest, sourceDirInfo.Mode()) -+ if err != nil { -+ return err -+ } -+ } else { -+ return err -+ } -+ } -+ -+ entries, err := os.ReadDir(src) -+ if err != nil { -+ return err -+ } -+ -+ for _, entry := range entries { -+ srcPath := filepath.Join(src, entry.Name()) -+ destPath := filepath.Join(dest, entry.Name()) -+ -+ if entry.IsDir() { -+ err = copyDir(srcPath, destPath) -+ if err != nil { -+ return err -+ } -+ } else { -+ err = copyFile(srcPath, destPath) -+ if err != nil { -+ return err -+ } -+ } -+ } -+ -+ return nil -+} -+ -+const ( -+ etlLibvirtInit = "/etc/libvirt-init" -+ etcLibvirt = "/etc/libvirt" -+) -+ - func (l LibvirtWrapper) SetupLibvirt(customLogFilters *string) (err error) { -+ if _, err = os.Stat(etlLibvirtInit); err == nil { -+ if err = copyDir(etlLibvirtInit, etcLibvirt); err != nil { -+ return fmt.Errorf("failed to copy %q to %q: %w", etlLibvirtInit, etcLibvirt, err) -+ } -+ } -+ - runtimeQemuConfPath := qemuConfPath - if !l.root() { - runtimeQemuConfPath = qemuNonRootConfPath diff --git a/images/virt-artifact/patches/038-disable-unnecessary-libvirt-sockets.patch b/images/virt-artifact/patches/038-disable-unnecessary-libvirt-sockets.patch deleted file mode 100644 index 1246c301ea..0000000000 --- a/images/virt-artifact/patches/038-disable-unnecessary-libvirt-sockets.patch +++ /dev/null @@ -1,22 +0,0 @@ -diff --git a/pkg/virt-launcher/virtwrap/util/libvirt_helper.go b/pkg/virt-launcher/virtwrap/util/libvirt_helper.go -index b342c034f7..2c442ca60c 100644 ---- a/pkg/virt-launcher/virtwrap/util/libvirt_helper.go -+++ b/pkg/virt-launcher/virtwrap/util/libvirt_helper.go -@@ -218,7 +218,7 @@ func (l LibvirtWrapper) StartVirtquemud(stopChan chan struct{}) { - go func() { - for { - exitChan := make(chan struct{}) -- args := []string{"-f", "/var/run/libvirt/virtqemud.conf"} -+ args := []string{"-f", "/var/run/libvirt/virtqemud.conf", "--no-admin-srv", "--no-ro-srv"} - cmd := exec.Command("/usr/sbin/virtqemud", args...) - if l.user != 0 { - cmd.SysProcAttr = &syscall.SysProcAttr{ -@@ -273,7 +273,7 @@ func (l LibvirtWrapper) StartVirtquemud(stopChan chan struct{}) { - - func startVirtlogdLogging(stopChan chan struct{}, domainName string, nonRoot bool) { - for { -- cmd := exec.Command("/usr/sbin/virtlogd", "-f", "/etc/libvirt/virtlogd.conf") -+ cmd := exec.Command("/usr/sbin/virtlogd", "-f", "/etc/libvirt/virtlogd.conf", "--no-admin-srv") - - exitChan := make(chan struct{}) - diff --git a/images/virt-artifact/patches/039-get-applied-checksum.patch b/images/virt-artifact/patches/039-get-applied-checksum.patch deleted file mode 100644 index 7ac79f7ac6..0000000000 --- a/images/virt-artifact/patches/039-get-applied-checksum.patch +++ /dev/null @@ -1,1226 +0,0 @@ -diff --git a/pkg/handler-launcher-com/cmd/info/info.pb.go b/pkg/handler-launcher-com/cmd/info/info.pb.go -index b61aea7a28..2ac0a4c73a 100644 ---- a/pkg/handler-launcher-com/cmd/info/info.pb.go -+++ b/pkg/handler-launcher-com/cmd/info/info.pb.go -@@ -15,15 +15,12 @@ It has these top-level messages: - */ - package info - --import ( -- fmt "fmt" -- -- proto "github.com/golang/protobuf/proto" -- -- math "math" -+import proto "github.com/golang/protobuf/proto" -+import fmt "fmt" -+import math "math" - -+import ( - context "golang.org/x/net/context" -- - grpc "google.golang.org/grpc" - ) - -diff --git a/pkg/handler-launcher-com/cmd/v1/cmd.pb.go b/pkg/handler-launcher-com/cmd/v1/cmd.pb.go -index 51db398841..6f41c22374 100644 ---- a/pkg/handler-launcher-com/cmd/v1/cmd.pb.go -+++ b/pkg/handler-launcher-com/cmd/v1/cmd.pb.go -@@ -41,18 +41,16 @@ It has these top-level messages: - SEVInfoResponse - LaunchMeasurementResponse - InjectLaunchSecretRequest -+ VMIChecksumResponse - */ - package v1 - --import ( -- fmt "fmt" -- -- proto "github.com/golang/protobuf/proto" -- -- math "math" -+import proto "github.com/golang/protobuf/proto" -+import fmt "fmt" -+import math "math" - -+import ( - context "golang.org/x/net/context" -- - grpc "google.golang.org/grpc" - ) - -@@ -932,6 +930,30 @@ func (m *InjectLaunchSecretRequest) GetOptions() []byte { - return nil - } - -+type VMIChecksumResponse struct { -+ Response *Response `protobuf:"bytes,1,opt,name=response" json:"response,omitempty"` -+ Checksum string `protobuf:"bytes,2,opt,name=checksum" json:"checksum,omitempty"` -+} -+ -+func (m *VMIChecksumResponse) Reset() { *m = VMIChecksumResponse{} } -+func (m *VMIChecksumResponse) String() string { return proto.CompactTextString(m) } -+func (*VMIChecksumResponse) ProtoMessage() {} -+func (*VMIChecksumResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{31} } -+ -+func (m *VMIChecksumResponse) GetResponse() *Response { -+ if m != nil { -+ return m.Response -+ } -+ return nil -+} -+ -+func (m *VMIChecksumResponse) GetChecksum() string { -+ if m != nil { -+ return m.Checksum -+ } -+ return "" -+} -+ - func init() { - proto.RegisterType((*QemuVersionResponse)(nil), "kubevirt.cmd.v1.QemuVersionResponse") - proto.RegisterType((*VMI)(nil), "kubevirt.cmd.v1.VMI") -@@ -964,6 +986,7 @@ func init() { - proto.RegisterType((*SEVInfoResponse)(nil), "kubevirt.cmd.v1.SEVInfoResponse") - proto.RegisterType((*LaunchMeasurementResponse)(nil), "kubevirt.cmd.v1.LaunchMeasurementResponse") - proto.RegisterType((*InjectLaunchSecretRequest)(nil), "kubevirt.cmd.v1.InjectLaunchSecretRequest") -+ proto.RegisterType((*VMIChecksumResponse)(nil), "kubevirt.cmd.v1.VMIChecksumResponse") - } - - // Reference imports to suppress errors if they are not otherwise used. -@@ -1007,6 +1030,7 @@ type CmdClient interface { - GetSEVInfo(ctx context.Context, in *EmptyRequest, opts ...grpc.CallOption) (*SEVInfoResponse, error) - GetLaunchMeasurement(ctx context.Context, in *VMIRequest, opts ...grpc.CallOption) (*LaunchMeasurementResponse, error) - InjectLaunchSecret(ctx context.Context, in *InjectLaunchSecretRequest, opts ...grpc.CallOption) (*Response, error) -+ GetAppliedVMIChecksum(ctx context.Context, in *EmptyRequest, opts ...grpc.CallOption) (*VMIChecksumResponse, error) - } - - type cmdClient struct { -@@ -1287,6 +1311,15 @@ func (c *cmdClient) InjectLaunchSecret(ctx context.Context, in *InjectLaunchSecr - return out, nil - } - -+func (c *cmdClient) GetAppliedVMIChecksum(ctx context.Context, in *EmptyRequest, opts ...grpc.CallOption) (*VMIChecksumResponse, error) { -+ out := new(VMIChecksumResponse) -+ err := grpc.Invoke(ctx, "/kubevirt.cmd.v1.Cmd/GetAppliedVMIChecksum", in, out, c.cc, opts...) -+ if err != nil { -+ return nil, err -+ } -+ return out, nil -+} -+ - // Server API for Cmd service - - type CmdServer interface { -@@ -1320,6 +1353,7 @@ type CmdServer interface { - GetSEVInfo(context.Context, *EmptyRequest) (*SEVInfoResponse, error) - GetLaunchMeasurement(context.Context, *VMIRequest) (*LaunchMeasurementResponse, error) - InjectLaunchSecret(context.Context, *InjectLaunchSecretRequest) (*Response, error) -+ GetAppliedVMIChecksum(context.Context, *EmptyRequest) (*VMIChecksumResponse, error) - } - - func RegisterCmdServer(s *grpc.Server, srv CmdServer) { -@@ -1866,6 +1900,24 @@ func _Cmd_InjectLaunchSecret_Handler(srv interface{}, ctx context.Context, dec f - return interceptor(ctx, in, info, handler) - } - -+func _Cmd_GetAppliedVMIChecksum_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { -+ in := new(EmptyRequest) -+ if err := dec(in); err != nil { -+ return nil, err -+ } -+ if interceptor == nil { -+ return srv.(CmdServer).GetAppliedVMIChecksum(ctx, in) -+ } -+ info := &grpc.UnaryServerInfo{ -+ Server: srv, -+ FullMethod: "/kubevirt.cmd.v1.Cmd/GetAppliedVMIChecksum", -+ } -+ handler := func(ctx context.Context, req interface{}) (interface{}, error) { -+ return srv.(CmdServer).GetAppliedVMIChecksum(ctx, req.(*EmptyRequest)) -+ } -+ return interceptor(ctx, in, info, handler) -+} -+ - var _Cmd_serviceDesc = grpc.ServiceDesc{ - ServiceName: "kubevirt.cmd.v1.Cmd", - HandlerType: (*CmdServer)(nil), -@@ -1990,6 +2042,10 @@ var _Cmd_serviceDesc = grpc.ServiceDesc{ - MethodName: "InjectLaunchSecret", - Handler: _Cmd_InjectLaunchSecret_Handler, - }, -+ { -+ MethodName: "GetAppliedVMIChecksum", -+ Handler: _Cmd_GetAppliedVMIChecksum_Handler, -+ }, - }, - Streams: []grpc.StreamDesc{}, - Metadata: "pkg/handler-launcher-com/cmd/v1/cmd.proto", -@@ -1998,118 +2054,121 @@ var _Cmd_serviceDesc = grpc.ServiceDesc{ - func init() { proto.RegisterFile("pkg/handler-launcher-com/cmd/v1/cmd.proto", fileDescriptor0) } - - var fileDescriptor0 = []byte{ -- // 1802 bytes of a gzipped FileDescriptorProto -- 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x59, 0x5f, 0x6f, 0x23, 0xb7, -- 0x11, 0x3f, 0x59, 0xb2, 0x2d, 0x8d, 0xff, 0xe4, 0x8e, 0xfe, 0x93, 0xb5, 0xdb, 0xbb, 0x73, 0x89, -- 0xe2, 0xe0, 0x14, 0x89, 0xdd, 0xbb, 0x5c, 0x82, 0xe2, 0x50, 0x04, 0x17, 0xcb, 0xb2, 0xe3, 0xe4, -- 0x7c, 0xa7, 0xac, 0x6c, 0x1f, 0x9a, 0x36, 0x08, 0xe8, 0x5d, 0x5a, 0x66, 0xbd, 0x4b, 0x2a, 0x4b, -- 0xae, 0x7a, 0xca, 0x53, 0x81, 0x14, 0x7d, 0x28, 0xd0, 0xcf, 0xd7, 0xb7, 0x7e, 0x8b, 0x02, 0x7d, -- 0x0c, 0xc8, 0xe5, 0xca, 0x2b, 0xed, 0xae, 0x7d, 0x86, 0xf4, 0x64, 0x92, 0x33, 0xf3, 0x9b, 0x21, -- 0x39, 0x33, 0xfc, 0x69, 0x0d, 0x1f, 0xf5, 0xae, 0xba, 0xbb, 0x97, 0x84, 0xfb, 0x01, 0x8d, 0x3e, -- 0x09, 0x48, 0xcc, 0xbd, 0x4b, 0x1a, 0x7d, 0xe2, 0x89, 0x70, 0xd7, 0x0b, 0xfd, 0xdd, 0xfe, 0x53, -- 0xfd, 0x67, 0xa7, 0x17, 0x09, 0x25, 0xd0, 0x07, 0x57, 0xf1, 0x39, 0xed, 0xb3, 0x48, 0xed, 0xe8, -- 0xb5, 0xfe, 0x53, 0x7c, 0x01, 0x2b, 0xdf, 0xd2, 0x30, 0x3e, 0xa3, 0x91, 0x64, 0x82, 0xbb, 0x54, -- 0xf6, 0x04, 0x97, 0x14, 0x7d, 0x06, 0xf5, 0xc8, 0x8e, 0x9d, 0xca, 0x56, 0x65, 0x7b, 0xe1, 0xd9, -- 0xc6, 0xce, 0x98, 0xe9, 0x4e, 0xaa, 0xec, 0x0e, 0x55, 0x91, 0x03, 0xf3, 0xfd, 0x04, 0xc9, 0x99, -- 0xd9, 0xaa, 0x6c, 0x37, 0xdc, 0x74, 0x8a, 0x1f, 0x43, 0xf5, 0xec, 0xf8, 0xc8, 0x28, 0x84, 0xec, -- 0x6b, 0x29, 0xb8, 0x81, 0x5d, 0x74, 0xd3, 0x29, 0x7e, 0x0a, 0xd5, 0x66, 0xfb, 0x14, 0x2d, 0xc3, -- 0x0c, 0xf3, 0x8d, 0x6c, 0xc9, 0x9d, 0x61, 0x3e, 0xda, 0x84, 0xba, 0x64, 0xe7, 0x01, 0xe3, 0x5d, -- 0xe9, 0xcc, 0x6c, 0x55, 0xb7, 0x97, 0xdc, 0xe1, 0x1c, 0xef, 0xc2, 0x7c, 0x27, 0x19, 0xe7, 0xcc, -- 0x56, 0x61, 0xb6, 0x4f, 0x82, 0x98, 0x9a, 0x30, 0x6a, 0x6e, 0x32, 0xc1, 0x2d, 0x98, 0x6d, 0x93, -- 0x2e, 0x95, 0x5a, 0xec, 0x89, 0x98, 0x2b, 0x63, 0x51, 0x73, 0x93, 0x09, 0x42, 0x50, 0x8b, 0x39, -- 0x53, 0x36, 0x74, 0x33, 0xd6, 0x6b, 0x92, 0xfd, 0x44, 0x9d, 0xaa, 0x81, 0x36, 0x63, 0xfc, 0x1c, -- 0xe6, 0x8e, 0x69, 0x28, 0xa2, 0x01, 0x5a, 0x87, 0x39, 0x12, 0x66, 0x80, 0xec, 0xac, 0x08, 0x09, -- 0xff, 0xa7, 0x02, 0xb5, 0x26, 0x0d, 0x82, 0x5c, 0xac, 0xbb, 0x30, 0x17, 0x1a, 0x38, 0xa3, 0xbe, -- 0xf0, 0xec, 0xc3, 0xdc, 0x49, 0x27, 0xde, 0x5c, 0xab, 0x86, 0x3e, 0x86, 0xd9, 0x9e, 0xde, 0x86, -- 0x53, 0xdd, 0xaa, 0x6e, 0x2f, 0x3c, 0x5b, 0xcf, 0xe9, 0x9b, 0x4d, 0xba, 0x89, 0x12, 0xfa, 0x1c, -- 0x1a, 0x3e, 0x93, 0x8a, 0x70, 0x8f, 0x4a, 0xa7, 0x66, 0x2c, 0x9c, 0x9c, 0x85, 0x3d, 0x47, 0xf7, -- 0x5a, 0x15, 0x6d, 0x43, 0xcd, 0xeb, 0xc5, 0xd2, 0x99, 0x35, 0x26, 0xab, 0x39, 0x93, 0x66, 0xfb, -- 0xd4, 0x35, 0x1a, 0xf8, 0x25, 0xd4, 0x4f, 0x44, 0x4f, 0x04, 0xa2, 0x3b, 0x40, 0xcf, 0x01, 0x78, -- 0x1c, 0x92, 0x1f, 0x3c, 0x1a, 0x04, 0xd2, 0xa9, 0x18, 0xdb, 0xb5, 0xbc, 0x2d, 0x0d, 0x02, 0xb7, -- 0xa1, 0x15, 0xf5, 0x48, 0xe2, 0x7f, 0x55, 0x60, 0xae, 0x73, 0xbc, 0xc7, 0x84, 0x44, 0x18, 0x16, -- 0x43, 0xc2, 0xe3, 0x0b, 0xe2, 0xa9, 0x38, 0xa2, 0x91, 0x39, 0xa7, 0x86, 0x3b, 0xb2, 0xa6, 0xb3, -- 0xa8, 0x17, 0x09, 0x3f, 0xf6, 0xd2, 0x13, 0x4e, 0xa7, 0xd9, 0x04, 0xac, 0x8e, 0x24, 0x20, 0xba, -- 0x0f, 0x55, 0x79, 0x15, 0x3b, 0x35, 0xb3, 0xaa, 0x87, 0xfa, 0xf2, 0x2e, 0x48, 0xc8, 0x82, 0x81, -- 0x33, 0x6b, 0x16, 0xed, 0x0c, 0xff, 0xb3, 0x02, 0xf5, 0x7d, 0x26, 0xaf, 0x8e, 0xf8, 0x85, 0x30, -- 0x4a, 0x22, 0x0a, 0x89, 0xb2, 0x81, 0xd8, 0x19, 0xda, 0x82, 0x85, 0x73, 0xe2, 0x5d, 0x31, 0xde, -- 0x3d, 0x60, 0x01, 0xb5, 0x61, 0x64, 0x97, 0xd0, 0x23, 0x00, 0x1d, 0x2f, 0x09, 0x3a, 0x69, 0xfe, -- 0xd4, 0xdc, 0xcc, 0x8a, 0x46, 0xd0, 0x47, 0x92, 0x2a, 0xd4, 0x8c, 0x42, 0x76, 0x09, 0xff, 0xaf, -- 0x02, 0x4b, 0xcd, 0x20, 0x96, 0x8a, 0x46, 0x4d, 0xc1, 0x2f, 0x58, 0x17, 0xed, 0x00, 0x6a, 0xbd, -- 0xeb, 0x11, 0xee, 0xeb, 0xf8, 0x64, 0x8b, 0x93, 0xf3, 0x80, 0x26, 0xa9, 0x54, 0x77, 0x0b, 0x24, -- 0xe8, 0x8f, 0xb0, 0x71, 0x10, 0x51, 0xaa, 0xf3, 0xc1, 0xa5, 0x3d, 0x11, 0x29, 0xc6, 0xbb, 0xfb, -- 0x4c, 0x26, 0x66, 0x33, 0xc6, 0xac, 0x5c, 0x01, 0xbd, 0x00, 0x67, 0x4f, 0x78, 0x97, 0x72, 0x9f, -- 0xc9, 0x5e, 0x40, 0x06, 0x07, 0x22, 0x6a, 0x1d, 0x1c, 0x1d, 0xc6, 0x54, 0x2a, 0x69, 0xf6, 0x53, -- 0x77, 0x4b, 0xe5, 0xda, 0xb6, 0x43, 0x23, 0x46, 0x82, 0xa6, 0xe0, 0x52, 0x04, 0xf4, 0x95, 0xb8, -- 0x76, 0x5c, 0x4b, 0x6c, 0xcb, 0xe4, 0xf8, 0x53, 0xd8, 0x38, 0xe2, 0x8a, 0x46, 0x17, 0xc4, 0xa3, -- 0x7b, 0x8c, 0xfb, 0x8c, 0x77, 0x8f, 0x59, 0x37, 0x22, 0x4a, 0xdf, 0xe3, 0xba, 0x2e, 0x3e, 0x75, -- 0x29, 0xfc, 0xf4, 0x42, 0x92, 0x19, 0xfe, 0xef, 0x3c, 0xac, 0x9d, 0x25, 0x87, 0x77, 0x4c, 0xbc, -- 0x4b, 0xc6, 0xe9, 0x9b, 0x9e, 0x36, 0x90, 0xe8, 0x1b, 0x58, 0x1d, 0x15, 0x24, 0x99, 0x66, 0xfb, -- 0x5a, 0xbe, 0xda, 0x12, 0xb1, 0x5b, 0x68, 0x84, 0x9e, 0xc3, 0xda, 0x31, 0x0d, 0xf7, 0x48, 0x10, -- 0x08, 0xc1, 0x3b, 0x8a, 0x28, 0xd9, 0xa6, 0x11, 0x13, 0xc9, 0x69, 0x2e, 0xb9, 0xc5, 0x42, 0xf4, -- 0x7b, 0x58, 0x69, 0x47, 0x54, 0xaf, 0x7b, 0x44, 0x51, 0xff, 0x4c, 0x04, 0x71, 0x68, 0xeb, 0xb7, -- 0xe1, 0x16, 0x89, 0x74, 0x03, 0x56, 0xb6, 0xa6, 0xcc, 0x79, 0x15, 0x35, 0xe0, 0xb4, 0xe8, 0xdc, -- 0xa1, 0x2a, 0xea, 0x40, 0xc3, 0x24, 0x80, 0xce, 0x5d, 0x5b, 0xb9, 0x9f, 0xe5, 0xec, 0x0a, 0x8f, -- 0x69, 0x67, 0x68, 0xd7, 0xe2, 0x2a, 0x1a, 0xb8, 0xd7, 0x38, 0x25, 0x59, 0x37, 0x57, 0x9a, 0x75, -- 0xfb, 0xb0, 0xe4, 0x65, 0xd3, 0xd6, 0x99, 0x37, 0x1b, 0x78, 0x94, 0x6f, 0x03, 0x59, 0x2d, 0x77, -- 0xd4, 0x08, 0xfd, 0x5c, 0x81, 0x0d, 0x96, 0xa6, 0xc1, 0xbe, 0x08, 0x09, 0xe3, 0x5f, 0x2a, 0x45, -- 0xbc, 0xcb, 0x90, 0x72, 0xe5, 0xd4, 0xcd, 0xde, 0x5a, 0xef, 0xb9, 0xb7, 0xa3, 0x32, 0x9c, 0x64, -- 0xaf, 0xe5, 0x7e, 0x10, 0x07, 0x34, 0x14, 0x0e, 0x93, 0xd0, 0x69, 0x18, 0xef, 0x5f, 0xdc, 0xd5, -- 0xfb, 0x10, 0x20, 0x71, 0x5b, 0x80, 0xbc, 0xf9, 0x16, 0x96, 0x47, 0x2f, 0x42, 0x37, 0xae, 0x2b, -- 0x3a, 0xb0, 0xd9, 0xae, 0x87, 0x68, 0x37, 0xfb, 0xb8, 0x15, 0x25, 0x46, 0xda, 0xbd, 0xec, 0xbb, -- 0xf7, 0x62, 0xe6, 0x0f, 0x95, 0xcd, 0x57, 0xf0, 0xe8, 0xe6, 0x53, 0x28, 0x70, 0x34, 0xf2, 0x8a, -- 0x36, 0xb2, 0x68, 0x3f, 0xc2, 0x87, 0x25, 0xbb, 0x2a, 0x80, 0x79, 0x39, 0x1a, 0xef, 0xef, 0x72, -- 0xf1, 0x96, 0x56, 0x7b, 0xc6, 0x25, 0xee, 0x03, 0x9c, 0x1d, 0x1f, 0xb9, 0xf4, 0x47, 0xdd, 0x60, -- 0xd0, 0x13, 0xa8, 0xf6, 0x43, 0x66, 0x6b, 0x38, 0xff, 0x38, 0x69, 0x4d, 0xad, 0x80, 0x5e, 0xc2, -- 0xbc, 0x48, 0xae, 0xc1, 0x7a, 0x7f, 0xf2, 0x7e, 0x97, 0xe6, 0xa6, 0x66, 0xf8, 0x04, 0xee, 0x5f, -- 0xc7, 0x73, 0x47, 0xef, 0xce, 0xa8, 0xf7, 0xc5, 0x6b, 0xd4, 0x9f, 0x2b, 0xb0, 0xd0, 0x7a, 0x47, -- 0xbd, 0x14, 0xf1, 0x11, 0x80, 0x6f, 0x6e, 0xe5, 0x35, 0x09, 0xa9, 0x3d, 0xbc, 0xcc, 0x8a, 0x46, -- 0x6a, 0x8a, 0x30, 0x24, 0xdc, 0x4f, 0x9f, 0x3c, 0x3b, 0xd5, 0x5c, 0xe3, 0xcb, 0xa8, 0x9b, 0x36, -- 0x13, 0x33, 0x46, 0x4f, 0x60, 0x59, 0xb1, 0x90, 0x8a, 0x58, 0x75, 0xa8, 0x27, 0xb8, 0x2f, 0x4d, -- 0x0f, 0x99, 0x75, 0xc7, 0x56, 0xf1, 0x32, 0x2c, 0xb6, 0xc2, 0x9e, 0x1a, 0xd8, 0x28, 0xf0, 0x17, -- 0x50, 0x77, 0x33, 0x5c, 0x4e, 0xc6, 0x9e, 0x47, 0xa5, 0xb4, 0x0f, 0x4c, 0x3a, 0xd5, 0x92, 0x90, -- 0x4a, 0x49, 0xba, 0x69, 0x62, 0xa4, 0x53, 0xfc, 0x03, 0x2c, 0x27, 0xb9, 0x35, 0x29, 0x91, 0x5c, -- 0x87, 0xb9, 0x64, 0xf3, 0xd6, 0x83, 0x9d, 0x61, 0x0e, 0x2b, 0x89, 0x03, 0xd3, 0x5d, 0x27, 0xf5, -- 0xb2, 0x05, 0x0b, 0xfe, 0x35, 0x5a, 0xfa, 0x88, 0x67, 0x96, 0xf0, 0x3b, 0x78, 0x60, 0x1e, 0x34, -- 0x53, 0x4d, 0x13, 0x7a, 0xfb, 0x18, 0x1e, 0x74, 0xc7, 0xb1, 0xac, 0xcf, 0xbc, 0x00, 0xff, 0xa3, -- 0x02, 0x6b, 0xc6, 0xf5, 0xa9, 0xa4, 0xd1, 0x2b, 0x26, 0xd5, 0xa4, 0xee, 0x9f, 0xc3, 0x5a, 0xb7, -- 0x08, 0xcf, 0x86, 0x50, 0x2c, 0xc4, 0xff, 0xae, 0x80, 0x63, 0xc2, 0xd0, 0x9c, 0x46, 0x0e, 0xa4, -- 0xa2, 0xe1, 0xc4, 0xc7, 0xfe, 0x02, 0x9c, 0x6e, 0x09, 0xa4, 0x0d, 0xa6, 0x54, 0x8e, 0x07, 0xb0, -- 0x98, 0x94, 0xcd, 0x64, 0x21, 0x6c, 0x42, 0x9d, 0xbe, 0x63, 0xaa, 0x29, 0xfc, 0xc4, 0xe5, 0xac, -- 0x3b, 0x9c, 0xeb, 0xdc, 0x93, 0xca, 0x7f, 0x13, 0x2b, 0x4b, 0x21, 0xed, 0x0c, 0x7f, 0x07, 0xf7, -- 0xcd, 0x49, 0xb4, 0x35, 0x51, 0x7e, 0xcf, 0xb2, 0xcd, 0x17, 0xe2, 0x4c, 0x61, 0x21, 0x7e, 0x6d, -- 0xf3, 0x2c, 0xc1, 0x9e, 0x68, 0x6f, 0x58, 0xc0, 0x92, 0xe6, 0x74, 0x3f, 0xd1, 0xbb, 0x76, 0xab, -- 0xcf, 0x61, 0x3d, 0xe6, 0x17, 0xc6, 0xf4, 0xa4, 0x28, 0xe8, 0x12, 0x29, 0x7e, 0x0b, 0x0f, 0x92, -- 0x5f, 0x28, 0xfb, 0x71, 0xd8, 0xbb, 0xab, 0xd3, 0x4d, 0xa8, 0xfb, 0x71, 0xd8, 0x6b, 0x13, 0x75, -- 0x69, 0x2f, 0x7f, 0x38, 0xc7, 0xe7, 0xf0, 0x41, 0xa7, 0x75, 0x36, 0x8d, 0xda, 0xd3, 0xcd, 0x8c, -- 0xf6, 0x0d, 0x2b, 0xb2, 0x8d, 0xd8, 0x4e, 0xf1, 0xdf, 0x2b, 0xb0, 0xf1, 0xca, 0xfc, 0x66, 0x3e, -- 0xa6, 0x44, 0xc6, 0x11, 0xd5, 0x0f, 0xe2, 0x14, 0x4a, 0x3d, 0x18, 0xc7, 0xb4, 0x8e, 0xf3, 0x02, -- 0xfc, 0xbd, 0xe6, 0xbb, 0x7f, 0xa5, 0x9e, 0x4a, 0xe2, 0xe8, 0x50, 0x2f, 0xa2, 0x6a, 0x6a, 0x4f, -- 0xcd, 0xb3, 0xff, 0xaf, 0x40, 0xb5, 0x19, 0xfa, 0xe8, 0x35, 0xa0, 0xce, 0x80, 0x7b, 0xa3, 0xcf, -- 0x1d, 0xfa, 0x55, 0x21, 0x64, 0xe2, 0x7c, 0xb3, 0x7c, 0xb3, 0xf8, 0x1e, 0x7a, 0x03, 0x2b, 0x6d, -- 0x12, 0x4b, 0x3a, 0x35, 0xc0, 0x6f, 0x61, 0xed, 0x94, 0xf7, 0xa6, 0x0a, 0xd9, 0x81, 0xd5, 0xa4, -- 0x16, 0xc6, 0x10, 0xf3, 0x5c, 0x74, 0xa4, 0x64, 0x6e, 0x06, 0x75, 0x61, 0xfd, 0xd4, 0x56, 0xc2, -- 0xd4, 0x02, 0x3d, 0x01, 0xa7, 0x23, 0x2e, 0x94, 0x4b, 0xcf, 0x85, 0x50, 0x53, 0x43, 0x75, 0x61, -- 0xbd, 0x73, 0x19, 0x2b, 0x5f, 0xfc, 0x8d, 0x4f, 0x0d, 0xf3, 0x35, 0xa0, 0x6f, 0x58, 0x10, 0x4c, -- 0x0d, 0xaf, 0x0d, 0xab, 0xfb, 0x34, 0xa0, 0x6a, 0x7a, 0x67, 0xf9, 0x16, 0xd6, 0x12, 0xc6, 0x36, -- 0x0e, 0xf9, 0x9b, 0xfc, 0x97, 0x95, 0x31, 0x66, 0x77, 0x6b, 0xc6, 0xeb, 0x0a, 0x1a, 0x1a, 0x9d, -- 0x90, 0xa8, 0x4b, 0xd5, 0x04, 0x91, 0xfe, 0x09, 0x1e, 0x36, 0x09, 0xf7, 0xe8, 0xd8, 0x69, 0x5e, -- 0xff, 0xda, 0x9d, 0xec, 0xea, 0x59, 0x97, 0x93, 0x20, 0x09, 0xb2, 0x2d, 0xfc, 0x66, 0x40, 0x09, -- 0x8f, 0x7b, 0x13, 0x60, 0xfe, 0x19, 0x1e, 0x1f, 0x30, 0x4e, 0x02, 0x36, 0x9e, 0xf8, 0xd3, 0x08, -- 0xf8, 0x35, 0xa0, 0xaf, 0x84, 0xea, 0x05, 0x71, 0xf7, 0x2b, 0x21, 0xd5, 0x3e, 0xed, 0x33, 0x8f, -- 0xca, 0x09, 0xf0, 0x8e, 0xa1, 0x71, 0x48, 0x55, 0xc2, 0x16, 0xd1, 0xc3, 0x9c, 0x66, 0x96, 0xf7, -- 0x6e, 0x3e, 0xce, 0xff, 0x84, 0x1a, 0xa1, 0xb1, 0x26, 0xa9, 0x96, 0x87, 0x70, 0x86, 0x1b, 0xde, -- 0x86, 0xf9, 0xdb, 0x12, 0xcc, 0x11, 0xe6, 0x6a, 0x5a, 0xd4, 0xe2, 0x21, 0x55, 0x43, 0x96, 0x79, -- 0x1b, 0x2c, 0xce, 0x89, 0x73, 0x04, 0xd5, 0x80, 0xd6, 0x0f, 0xa9, 0x61, 0x73, 0xb7, 0xc6, 0xf9, -- 0xa4, 0x18, 0x30, 0xc7, 0x04, 0xef, 0xa1, 0xbf, 0x98, 0x23, 0xc8, 0xb0, 0xb2, 0xdb, 0xa0, 0x3f, -- 0x2a, 0x86, 0x2e, 0xe2, 0x75, 0xf7, 0xd0, 0x1e, 0xd4, 0x34, 0xfb, 0xb9, 0x0d, 0xf3, 0xc6, 0x3b, -- 0x6f, 0x41, 0x4d, 0xb3, 0x43, 0xf4, 0xeb, 0x3c, 0xc6, 0xf5, 0x6f, 0xad, 0xcd, 0x87, 0x25, 0xd2, -- 0x4c, 0x33, 0x6e, 0x0c, 0xd9, 0x58, 0x41, 0xd3, 0x18, 0x67, 0x81, 0x65, 0x77, 0x92, 0x25, 0x73, -- 0xa6, 0x7a, 0x9c, 0xb1, 0xaa, 0x19, 0x92, 0x26, 0x84, 0x4b, 0xbe, 0xf9, 0x66, 0x18, 0xd5, 0x6d, -- 0x3d, 0x4f, 0xdf, 0x4d, 0xe6, 0x53, 0xfe, 0xdd, 0xd3, 0xb3, 0xe0, 0xff, 0x00, 0xb6, 0x8f, 0xe4, -- 0x58, 0x43, 0xb3, 0x7d, 0x2a, 0x27, 0x7c, 0xec, 0x72, 0x98, 0xf6, 0x93, 0xfa, 0x24, 0x7c, 0x04, -- 0x0e, 0xa9, 0xb2, 0x84, 0xf1, 0xb6, 0xed, 0x6f, 0xe5, 0x3f, 0xfb, 0x8d, 0x32, 0x4d, 0x7c, 0x0f, -- 0x11, 0x58, 0x3d, 0xa4, 0x2a, 0x47, 0x0e, 0x6f, 0x0e, 0x31, 0xff, 0x75, 0xa3, 0x94, 0x5d, 0xe2, -- 0x7b, 0xe8, 0x7b, 0x40, 0x79, 0xea, 0x87, 0x8a, 0xbe, 0x90, 0x94, 0xf0, 0xc3, 0x1b, 0x8f, 0x64, -- 0xaf, 0xf6, 0xdd, 0x4c, 0xff, 0xe9, 0xf9, 0x9c, 0xf9, 0xdf, 0xcf, 0xa7, 0xbf, 0x04, 0x00, 0x00, -- 0xff, 0xff, 0x7a, 0xa3, 0xf8, 0x64, 0x28, 0x1a, 0x00, 0x00, -+ // 1843 bytes of a gzipped FileDescriptorProto -+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x59, 0x5f, 0x73, 0xdb, 0xc6, -+ 0x11, 0x17, 0x45, 0x4a, 0x26, 0x57, 0x7f, 0x12, 0x9f, 0xfe, 0x04, 0x52, 0x6b, 0x5b, 0xc5, 0x74, -+ 0x3c, 0x4a, 0x27, 0x91, 0x6a, 0xc7, 0xc9, 0x74, 0x3c, 0x9d, 0x8c, 0x2d, 0x8a, 0x52, 0x94, 0x98, -+ 0x36, 0x03, 0x4a, 0xf2, 0x34, 0x6d, 0x9a, 0x39, 0x01, 0x27, 0xf2, 0x2a, 0xe0, 0x0e, 0xc1, 0x1d, -+ 0x58, 0x33, 0x4f, 0x9d, 0x49, 0xa7, 0x0f, 0x9d, 0xe9, 0xe7, 0x6b, 0x9f, 0xfa, 0x2d, 0xfa, 0xde, -+ 0xb9, 0xc3, 0x81, 0x02, 0x09, 0x40, 0xb2, 0x86, 0x7c, 0x22, 0xf6, 0x6e, 0xf7, 0xb7, 0x7b, 0x77, -+ 0xbb, 0x7b, 0x3f, 0x80, 0xf0, 0x71, 0x78, 0xd5, 0xdb, 0xef, 0x63, 0xe6, 0xf9, 0x24, 0xfa, 0xd4, -+ 0xc7, 0x31, 0x73, 0xfb, 0x24, 0xfa, 0xd4, 0xe5, 0xc1, 0xbe, 0x1b, 0x78, 0xfb, 0x83, 0x27, 0xea, -+ 0x67, 0x2f, 0x8c, 0xb8, 0xe4, 0xe8, 0x83, 0xab, 0xf8, 0x82, 0x0c, 0x68, 0x24, 0xf7, 0xd4, 0xd8, -+ 0xe0, 0x89, 0x7d, 0x09, 0x6b, 0xdf, 0x92, 0x20, 0x3e, 0x27, 0x91, 0xa0, 0x9c, 0x39, 0x44, 0x84, -+ 0x9c, 0x09, 0x82, 0x3e, 0x87, 0x7a, 0x64, 0x9e, 0xad, 0xca, 0x4e, 0x65, 0x77, 0xe9, 0xe9, 0xd6, -+ 0xde, 0x84, 0xe9, 0x5e, 0xaa, 0xec, 0x8c, 0x54, 0x91, 0x05, 0xf7, 0x06, 0x09, 0x92, 0x35, 0xbf, -+ 0x53, 0xd9, 0x6d, 0x38, 0xa9, 0x68, 0x3f, 0x82, 0xea, 0x79, 0xfb, 0x44, 0x2b, 0x04, 0xf4, 0x6b, -+ 0xc1, 0x99, 0x86, 0x5d, 0x76, 0x52, 0xd1, 0x7e, 0x02, 0xd5, 0x66, 0xe7, 0x0c, 0xad, 0xc2, 0x3c, -+ 0xf5, 0xf4, 0xdc, 0x8a, 0x33, 0x4f, 0x3d, 0xb4, 0x0d, 0x75, 0x41, 0x2f, 0x7c, 0xca, 0x7a, 0xc2, -+ 0x9a, 0xdf, 0xa9, 0xee, 0xae, 0x38, 0x23, 0xd9, 0xde, 0x87, 0x7b, 0xdd, 0xe4, 0x39, 0x67, 0xb6, -+ 0x0e, 0x0b, 0x03, 0xec, 0xc7, 0x44, 0x87, 0x51, 0x73, 0x12, 0xc1, 0x6e, 0xc1, 0x42, 0x07, 0xf7, -+ 0x88, 0x50, 0xd3, 0x2e, 0x8f, 0x99, 0xd4, 0x16, 0x35, 0x27, 0x11, 0x10, 0x82, 0x5a, 0xcc, 0xa8, -+ 0x34, 0xa1, 0xeb, 0x67, 0x35, 0x26, 0xe8, 0x4f, 0xc4, 0xaa, 0x6a, 0x68, 0xfd, 0x6c, 0x3f, 0x83, -+ 0xc5, 0x36, 0x09, 0x78, 0x34, 0x44, 0x9b, 0xb0, 0x88, 0x83, 0x0c, 0x90, 0x91, 0x8a, 0x90, 0xec, -+ 0x7f, 0x57, 0xa0, 0xd6, 0x24, 0xbe, 0x9f, 0x8b, 0x75, 0x1f, 0x16, 0x03, 0x0d, 0xa7, 0xd5, 0x97, -+ 0x9e, 0x7e, 0x94, 0xdb, 0xe9, 0xc4, 0x9b, 0x63, 0xd4, 0xd0, 0x27, 0xb0, 0x10, 0xaa, 0x65, 0x58, -+ 0xd5, 0x9d, 0xea, 0xee, 0xd2, 0xd3, 0xcd, 0x9c, 0xbe, 0x5e, 0xa4, 0x93, 0x28, 0xa1, 0x2f, 0xa0, -+ 0xe1, 0x51, 0x21, 0x31, 0x73, 0x89, 0xb0, 0x6a, 0xda, 0xc2, 0xca, 0x59, 0x98, 0x7d, 0x74, 0xae, -+ 0x55, 0xd1, 0x2e, 0xd4, 0xdc, 0x30, 0x16, 0xd6, 0x82, 0x36, 0x59, 0xcf, 0x99, 0x34, 0x3b, 0x67, -+ 0x8e, 0xd6, 0xb0, 0x5f, 0x40, 0xfd, 0x94, 0x87, 0xdc, 0xe7, 0xbd, 0x21, 0x7a, 0x06, 0xc0, 0xe2, -+ 0x00, 0xff, 0xe0, 0x12, 0xdf, 0x17, 0x56, 0x45, 0xdb, 0x6e, 0xe4, 0x6d, 0x89, 0xef, 0x3b, 0x0d, -+ 0xa5, 0xa8, 0x9e, 0x84, 0xfd, 0xcf, 0x0a, 0x2c, 0x76, 0xdb, 0x07, 0x94, 0x0b, 0x64, 0xc3, 0x72, -+ 0x80, 0x59, 0x7c, 0x89, 0x5d, 0x19, 0x47, 0x24, 0xd2, 0xfb, 0xd4, 0x70, 0xc6, 0xc6, 0x54, 0x16, -+ 0x85, 0x11, 0xf7, 0x62, 0x37, 0xdd, 0xe1, 0x54, 0xcc, 0x26, 0x60, 0x75, 0x2c, 0x01, 0xd1, 0x87, -+ 0x50, 0x15, 0x57, 0xb1, 0x55, 0xd3, 0xa3, 0xea, 0x51, 0x1d, 0xde, 0x25, 0x0e, 0xa8, 0x3f, 0xb4, -+ 0x16, 0xf4, 0xa0, 0x91, 0xec, 0x7f, 0x54, 0xa0, 0x7e, 0x48, 0xc5, 0xd5, 0x09, 0xbb, 0xe4, 0x5a, -+ 0x89, 0x47, 0x01, 0x96, 0x26, 0x10, 0x23, 0xa1, 0x1d, 0x58, 0xba, 0xc0, 0xee, 0x15, 0x65, 0xbd, -+ 0x23, 0xea, 0x13, 0x13, 0x46, 0x76, 0x08, 0x3d, 0x04, 0x50, 0xf1, 0x62, 0xbf, 0x9b, 0xe6, 0x4f, -+ 0xcd, 0xc9, 0x8c, 0x28, 0x04, 0xb5, 0x25, 0xa9, 0x42, 0x4d, 0x2b, 0x64, 0x87, 0xec, 0xff, 0x55, -+ 0x60, 0xa5, 0xe9, 0xc7, 0x42, 0x92, 0xa8, 0xc9, 0xd9, 0x25, 0xed, 0xa1, 0x3d, 0x40, 0xad, 0x77, -+ 0x21, 0x66, 0x9e, 0x8a, 0x4f, 0xb4, 0x18, 0xbe, 0xf0, 0x49, 0x92, 0x4a, 0x75, 0xa7, 0x60, 0x06, -+ 0xfd, 0x1e, 0xb6, 0x8e, 0x22, 0x42, 0x54, 0x3e, 0x38, 0x24, 0xe4, 0x91, 0xa4, 0xac, 0x77, 0x48, -+ 0x45, 0x62, 0x36, 0xaf, 0xcd, 0xca, 0x15, 0xd0, 0x73, 0xb0, 0x0e, 0xb8, 0xdb, 0x17, 0x87, 0x54, -+ 0x84, 0x3e, 0x1e, 0x1e, 0xf1, 0xa8, 0x75, 0x74, 0x72, 0x1c, 0x13, 0x21, 0x85, 0x5e, 0x4f, 0xdd, -+ 0x29, 0x9d, 0x57, 0xb6, 0x5d, 0x12, 0x51, 0xec, 0x37, 0x39, 0x13, 0xdc, 0x27, 0xaf, 0xf8, 0xb5, -+ 0xe3, 0x5a, 0x62, 0x5b, 0x36, 0x6f, 0x7f, 0x06, 0x5b, 0x27, 0x4c, 0x92, 0xe8, 0x12, 0xbb, 0xe4, -+ 0x80, 0x32, 0x8f, 0xb2, 0x5e, 0x9b, 0xf6, 0x22, 0x2c, 0xd5, 0x39, 0x6e, 0xaa, 0xe2, 0x93, 0x7d, -+ 0xee, 0xa5, 0x07, 0x92, 0x48, 0xf6, 0x7f, 0xef, 0xc1, 0xc6, 0x79, 0xb2, 0x79, 0x6d, 0xec, 0xf6, -+ 0x29, 0x23, 0x6f, 0x42, 0x65, 0x20, 0xd0, 0x37, 0xb0, 0x3e, 0x3e, 0x91, 0x64, 0x9a, 0xe9, 0x6b, -+ 0xf9, 0x6a, 0x4b, 0xa6, 0x9d, 0x42, 0x23, 0xf4, 0x0c, 0x36, 0xda, 0x24, 0x38, 0xc0, 0xbe, 0xcf, -+ 0x39, 0xeb, 0x4a, 0x2c, 0x45, 0x87, 0x44, 0x94, 0x27, 0xbb, 0xb9, 0xe2, 0x14, 0x4f, 0xa2, 0xdf, -+ 0xc2, 0x5a, 0x27, 0x22, 0x6a, 0xdc, 0xc5, 0x92, 0x78, 0xe7, 0xdc, 0x8f, 0x03, 0x53, 0xbf, 0x0d, -+ 0xa7, 0x68, 0x4a, 0x35, 0x60, 0x69, 0x6a, 0x4a, 0xef, 0x57, 0x51, 0x03, 0x4e, 0x8b, 0xce, 0x19, -+ 0xa9, 0xa2, 0x2e, 0x34, 0x74, 0x02, 0xa8, 0xdc, 0x35, 0x95, 0xfb, 0x79, 0xce, 0xae, 0x70, 0x9b, -+ 0xf6, 0x46, 0x76, 0x2d, 0x26, 0xa3, 0xa1, 0x73, 0x8d, 0x53, 0x92, 0x75, 0x8b, 0xa5, 0x59, 0x77, -+ 0x08, 0x2b, 0x6e, 0x36, 0x6d, 0xad, 0x7b, 0x7a, 0x01, 0x0f, 0xf3, 0x6d, 0x20, 0xab, 0xe5, 0x8c, -+ 0x1b, 0xa1, 0x9f, 0x2b, 0xb0, 0x45, 0xd3, 0x34, 0x38, 0xe4, 0x01, 0xa6, 0xec, 0xa5, 0x94, 0xd8, -+ 0xed, 0x07, 0x84, 0x49, 0xab, 0xae, 0xd7, 0xd6, 0x7a, 0xcf, 0xb5, 0x9d, 0x94, 0xe1, 0x24, 0x6b, -+ 0x2d, 0xf7, 0x83, 0x18, 0xa0, 0xd1, 0xe4, 0x28, 0x09, 0xad, 0x86, 0xf6, 0xfe, 0xe5, 0x5d, 0xbd, -+ 0x8f, 0x00, 0x12, 0xb7, 0x05, 0xc8, 0xdb, 0x6f, 0x61, 0x75, 0xfc, 0x20, 0x54, 0xe3, 0xba, 0x22, -+ 0x43, 0x93, 0xed, 0xea, 0x11, 0xed, 0x67, 0x2f, 0xb7, 0xa2, 0xc4, 0x48, 0xbb, 0x97, 0xb9, 0xf7, -+ 0x9e, 0xcf, 0xff, 0xae, 0xb2, 0xfd, 0x0a, 0x1e, 0xde, 0xbc, 0x0b, 0x05, 0x8e, 0xc6, 0x6e, 0xd1, -+ 0x46, 0x16, 0xed, 0x47, 0xf8, 0xa8, 0x64, 0x55, 0x05, 0x30, 0x2f, 0xc6, 0xe3, 0xfd, 0x4d, 0x2e, -+ 0xde, 0xd2, 0x6a, 0xcf, 0xb8, 0xb4, 0x07, 0x00, 0xe7, 0xed, 0x13, 0x87, 0xfc, 0xa8, 0x1a, 0x0c, -+ 0x7a, 0x0c, 0xd5, 0x41, 0x40, 0x4d, 0x0d, 0xe7, 0x2f, 0x27, 0xa5, 0xa9, 0x14, 0xd0, 0x0b, 0xb8, -+ 0xc7, 0x93, 0x63, 0x30, 0xde, 0x1f, 0xbf, 0xdf, 0xa1, 0x39, 0xa9, 0x99, 0x7d, 0x0a, 0x1f, 0x5e, -+ 0xc7, 0x73, 0x47, 0xef, 0xd6, 0xb8, 0xf7, 0xe5, 0x6b, 0xd4, 0x9f, 0x2b, 0xb0, 0xd4, 0x7a, 0x47, -+ 0xdc, 0x14, 0xf1, 0x21, 0x80, 0xa7, 0x4f, 0xe5, 0x35, 0x0e, 0x88, 0xd9, 0xbc, 0xcc, 0x88, 0x42, -+ 0x6a, 0xf2, 0x20, 0xc0, 0xcc, 0x4b, 0xaf, 0x3c, 0x23, 0x2a, 0xae, 0xf1, 0x32, 0xea, 0xa5, 0xcd, -+ 0x44, 0x3f, 0xa3, 0xc7, 0xb0, 0x2a, 0x69, 0x40, 0x78, 0x2c, 0xbb, 0xc4, 0xe5, 0xcc, 0x13, 0xba, -+ 0x87, 0x2c, 0x38, 0x13, 0xa3, 0xf6, 0x2a, 0x2c, 0xb7, 0x82, 0x50, 0x0e, 0x4d, 0x14, 0xf6, 0x97, -+ 0x50, 0x77, 0x32, 0x5c, 0x4e, 0xc4, 0xae, 0x4b, 0x84, 0x30, 0x17, 0x4c, 0x2a, 0xaa, 0x99, 0x80, -+ 0x08, 0x81, 0x7b, 0x69, 0x62, 0xa4, 0xa2, 0xfd, 0x03, 0xac, 0x26, 0xb9, 0x35, 0x2d, 0x91, 0xdc, -+ 0x84, 0xc5, 0x64, 0xf1, 0xc6, 0x83, 0x91, 0x6c, 0x06, 0x6b, 0x89, 0x03, 0xdd, 0x5d, 0xa7, 0xf5, -+ 0xb2, 0x03, 0x4b, 0xde, 0x35, 0x5a, 0x7a, 0x89, 0x67, 0x86, 0xec, 0x77, 0x70, 0x5f, 0x5f, 0x68, -+ 0xba, 0x9a, 0xa6, 0xf4, 0xf6, 0x09, 0xdc, 0xef, 0x4d, 0x62, 0x19, 0x9f, 0xf9, 0x09, 0xfb, 0xef, -+ 0x15, 0xd8, 0xd0, 0xae, 0xcf, 0x04, 0x89, 0x5e, 0x51, 0x21, 0xa7, 0x75, 0xff, 0x0c, 0x36, 0x7a, -+ 0x45, 0x78, 0x26, 0x84, 0xe2, 0x49, 0xfb, 0x5f, 0x15, 0xb0, 0x74, 0x18, 0x8a, 0xd3, 0x88, 0xa1, -+ 0x90, 0x24, 0x98, 0x7a, 0xdb, 0x9f, 0x83, 0xd5, 0x2b, 0x81, 0x34, 0xc1, 0x94, 0xce, 0xdb, 0x43, -+ 0x58, 0x4e, 0xca, 0x66, 0xba, 0x10, 0xb6, 0xa1, 0x4e, 0xde, 0x51, 0xd9, 0xe4, 0x5e, 0xe2, 0x72, -+ 0xc1, 0x19, 0xc9, 0x2a, 0xf7, 0x84, 0xf4, 0xde, 0xc4, 0xd2, 0x50, 0x48, 0x23, 0xd9, 0xdf, 0xc1, -+ 0x87, 0x7a, 0x27, 0x3a, 0x8a, 0x28, 0xbf, 0x67, 0xd9, 0xe6, 0x0b, 0x71, 0xbe, 0xb0, 0x10, 0xbf, -+ 0x36, 0x79, 0x96, 0x60, 0x4f, 0xb5, 0x36, 0x9b, 0xc3, 0x8a, 0xe2, 0x74, 0x3f, 0x91, 0xbb, 0x76, -+ 0xab, 0x2f, 0x60, 0x33, 0x66, 0x97, 0xda, 0xf4, 0xb4, 0x28, 0xe8, 0x92, 0x59, 0xfb, 0x2d, 0xdc, -+ 0x4f, 0xde, 0x50, 0x0e, 0xe3, 0x20, 0xbc, 0xab, 0xd3, 0x6d, 0xa8, 0x7b, 0x71, 0x10, 0x76, 0xb0, -+ 0xec, 0x9b, 0xc3, 0x1f, 0xc9, 0xf6, 0x05, 0x7c, 0xd0, 0x6d, 0x9d, 0xcf, 0xa2, 0xf6, 0x54, 0x33, -+ 0x23, 0x03, 0xcd, 0x8a, 0x4c, 0x23, 0x36, 0xa2, 0xfd, 0xb7, 0x0a, 0x6c, 0xbd, 0xd2, 0xef, 0xcc, -+ 0x6d, 0x82, 0x45, 0x1c, 0x11, 0x75, 0x21, 0xce, 0xa0, 0xd4, 0xfd, 0x49, 0x4c, 0xe3, 0x38, 0x3f, -+ 0x61, 0x7f, 0xaf, 0xf8, 0xee, 0x5f, 0x88, 0x2b, 0x93, 0x38, 0xba, 0xc4, 0x8d, 0x88, 0x9c, 0xdd, -+ 0x55, 0xd3, 0x87, 0xb5, 0xf3, 0xf6, 0x49, 0xb3, 0x4f, 0xdc, 0x2b, 0x11, 0x07, 0x33, 0xa8, 0x1c, -+ 0xd7, 0x40, 0xa5, 0xe7, 0x95, 0xca, 0x4f, 0xff, 0xb3, 0x0e, 0xd5, 0x66, 0xe0, 0xa1, 0xd7, 0x80, -+ 0xba, 0x43, 0xe6, 0x8e, 0x5f, 0xac, 0xe8, 0x17, 0x85, 0xc1, 0x27, 0xcb, 0xdc, 0x2e, 0xf7, 0x6d, -+ 0xcf, 0xa1, 0x37, 0xb0, 0xd6, 0xc1, 0xb1, 0x20, 0x33, 0x03, 0xfc, 0x16, 0x36, 0xce, 0x58, 0x38, -+ 0x53, 0xc8, 0x2e, 0xac, 0x27, 0x55, 0x37, 0x81, 0x98, 0x67, 0xbd, 0x63, 0xc5, 0x79, 0x33, 0xa8, -+ 0x03, 0x9b, 0x67, 0xa6, 0xe6, 0x66, 0x16, 0xe8, 0x29, 0x58, 0x5d, 0x7e, 0x29, 0x1d, 0x72, 0xc1, -+ 0xb9, 0x9c, 0x19, 0xaa, 0x03, 0x9b, 0xdd, 0x7e, 0x2c, 0x3d, 0xfe, 0x57, 0x36, 0x33, 0xcc, 0xd7, -+ 0x80, 0xbe, 0xa1, 0xbe, 0x3f, 0x33, 0xbc, 0x0e, 0xac, 0x1f, 0x12, 0x9f, 0xc8, 0xd9, 0xed, 0xe5, -+ 0x5b, 0xd8, 0x48, 0xb8, 0xe1, 0x24, 0xe4, 0xaf, 0xf2, 0xdf, 0x70, 0x26, 0x38, 0xe4, 0xad, 0x19, -+ 0xaf, 0x2a, 0x68, 0x64, 0x74, 0x8a, 0xa3, 0x1e, 0x91, 0x53, 0x44, 0xfa, 0x07, 0x78, 0xd0, 0xc4, -+ 0xcc, 0x25, 0x13, 0xbb, 0x79, 0xfd, 0x5e, 0x3d, 0xdd, 0xd1, 0xd3, 0x1e, 0xc3, 0x7e, 0x12, 0x64, -+ 0x87, 0x7b, 0x4d, 0x9f, 0x60, 0x16, 0x87, 0x53, 0x60, 0xfe, 0x11, 0x1e, 0x1d, 0x51, 0x86, 0x7d, -+ 0x3a, 0x99, 0xf8, 0xb3, 0x08, 0xf8, 0x35, 0xa0, 0xaf, 0xb8, 0x0c, 0xfd, 0xb8, 0xf7, 0x15, 0x17, -+ 0xf2, 0x90, 0x0c, 0xa8, 0x4b, 0xc4, 0x14, 0x78, 0x6d, 0x68, 0x1c, 0x13, 0x99, 0xf0, 0x52, 0xf4, -+ 0x20, 0xa7, 0x99, 0x65, 0xd8, 0xdb, 0x8f, 0xf2, 0x2f, 0x6b, 0x63, 0x84, 0x59, 0x27, 0xd5, 0xea, -+ 0x08, 0x4e, 0xb3, 0xd0, 0xdb, 0x30, 0x7f, 0x5d, 0x82, 0x39, 0xc6, 0x91, 0x75, 0x8b, 0x5a, 0x3e, -+ 0x26, 0x72, 0xc4, 0x67, 0x6f, 0x83, 0xb5, 0x73, 0xd3, 0x39, 0x2a, 0xac, 0x41, 0xeb, 0xc7, 0x44, -+ 0xf3, 0xc6, 0x5b, 0xe3, 0x7c, 0x5c, 0x0c, 0x98, 0xe3, 0x9c, 0x73, 0xe8, 0x4f, 0x7a, 0x0b, 0x32, -+ 0xfc, 0xef, 0x36, 0xe8, 0x8f, 0x8b, 0xa1, 0x8b, 0x18, 0xe4, 0x1c, 0x3a, 0x80, 0x9a, 0xe2, 0x59, -+ 0xb7, 0x61, 0xde, 0x78, 0xe6, 0x2d, 0xa8, 0x29, 0x1e, 0x8a, 0x7e, 0x99, 0xc7, 0xb8, 0x7e, 0xab, -+ 0xdb, 0x7e, 0x50, 0x32, 0x9b, 0x69, 0xc6, 0x8d, 0x11, 0xef, 0x2b, 0x68, 0x1a, 0x93, 0x7c, 0xb3, -+ 0xec, 0x4c, 0xb2, 0xb4, 0x51, 0x57, 0x8f, 0x35, 0x51, 0x35, 0x23, 0x7a, 0x86, 0xec, 0x92, 0xaf, -+ 0xcb, 0x19, 0xee, 0x76, 0x5b, 0xcf, 0x53, 0x67, 0x93, 0xf9, 0xd3, 0xe0, 0xee, 0xe9, 0x59, 0xf0, -+ 0x8f, 0x83, 0xe9, 0x23, 0x39, 0xd6, 0xd0, 0xec, 0x9c, 0x89, 0x29, 0x2f, 0xbb, 0x1c, 0xa6, 0xf9, -+ 0x78, 0x3f, 0x0d, 0x1f, 0x81, 0x63, 0x22, 0x0d, 0x35, 0xbd, 0x6d, 0xf9, 0x3b, 0xf9, 0x0f, 0x8c, -+ 0xe3, 0x9c, 0xd6, 0x9e, 0x43, 0x18, 0xd6, 0x8f, 0x89, 0xcc, 0xd1, 0xd0, 0x9b, 0x43, 0xcc, 0x7f, -+ 0x47, 0x29, 0xe5, 0xb1, 0xf6, 0x1c, 0xfa, 0x1e, 0x50, 0x9e, 0x64, 0xa2, 0xa2, 0x6f, 0x31, 0x25, -+ 0x4c, 0xf4, 0xe6, 0x2d, 0xf9, 0x33, 0x6c, 0x1c, 0x13, 0xf9, 0x32, 0x0c, 0x7d, 0x4a, 0xbc, 0x0c, -+ 0xdd, 0xbc, 0x7b, 0x72, 0x14, 0x70, 0x55, 0x7b, 0xee, 0xa0, 0xf6, 0xdd, 0xfc, 0xe0, 0xc9, 0xc5, -+ 0xa2, 0xfe, 0x17, 0xeb, 0xb3, 0xff, 0x07, 0x00, 0x00, 0xff, 0xff, 0xba, 0x43, 0xe7, 0x93, 0xf2, -+ 0x1a, 0x00, 0x00, - } -diff --git a/pkg/handler-launcher-com/cmd/v1/cmd.proto b/pkg/handler-launcher-com/cmd/v1/cmd.proto -index fd2591b7af..e2d6be51f1 100644 ---- a/pkg/handler-launcher-com/cmd/v1/cmd.proto -+++ b/pkg/handler-launcher-com/cmd/v1/cmd.proto -@@ -34,6 +34,7 @@ service Cmd { - rpc GetSEVInfo(EmptyRequest) returns (SEVInfoResponse) {} - rpc GetLaunchMeasurement(VMIRequest) returns (LaunchMeasurementResponse) {} - rpc InjectLaunchSecret(InjectLaunchSecretRequest) returns (Response) {} -+ rpc GetAppliedVMIChecksum(EmptyRequest) returns (VMIChecksumResponse) {} - } - - message QemuVersionResponse { -@@ -205,3 +206,8 @@ message InjectLaunchSecretRequest { - VMI vmi = 1; - bytes options = 2; - } -+ -+message VMIChecksumResponse { -+ Response response = 1; -+ string checksum = 2; -+} -diff --git a/pkg/handler-launcher-com/notify/info/info.pb.go b/pkg/handler-launcher-com/notify/info/info.pb.go -index 671ae85bec..35383632e3 100644 ---- a/pkg/handler-launcher-com/notify/info/info.pb.go -+++ b/pkg/handler-launcher-com/notify/info/info.pb.go -@@ -15,15 +15,12 @@ It has these top-level messages: - */ - package info - --import ( -- fmt "fmt" -- -- proto "github.com/golang/protobuf/proto" -- -- math "math" -+import proto "github.com/golang/protobuf/proto" -+import fmt "fmt" -+import math "math" - -+import ( - context "golang.org/x/net/context" -- - grpc "google.golang.org/grpc" - ) - -diff --git a/pkg/handler-launcher-com/notify/v1/notify.pb.go b/pkg/handler-launcher-com/notify/v1/notify.pb.go -index b8eed72ba0..0ff5f1746f 100644 ---- a/pkg/handler-launcher-com/notify/v1/notify.pb.go -+++ b/pkg/handler-launcher-com/notify/v1/notify.pb.go -@@ -16,15 +16,12 @@ It has these top-level messages: - */ - package v1 - --import ( -- fmt "fmt" -- -- proto "github.com/golang/protobuf/proto" -- -- math "math" -+import proto "github.com/golang/protobuf/proto" -+import fmt "fmt" -+import math "math" - -+import ( - context "golang.org/x/net/context" -- - grpc "google.golang.org/grpc" - ) - -diff --git a/pkg/hooks/info/api_info.pb.go b/pkg/hooks/info/api_info.pb.go -index 38f4f7229a..96ac568ef9 100755 ---- a/pkg/hooks/info/api_info.pb.go -+++ b/pkg/hooks/info/api_info.pb.go -@@ -16,15 +16,12 @@ It has these top-level messages: - */ - package info - --import ( -- fmt "fmt" -- -- proto "github.com/golang/protobuf/proto" -- -- math "math" -+import proto "github.com/golang/protobuf/proto" -+import fmt "fmt" -+import math "math" - -+import ( - context "golang.org/x/net/context" -- - grpc "google.golang.org/grpc" - ) - -diff --git a/pkg/hooks/v1alpha1/api_v1alpha1.pb.go b/pkg/hooks/v1alpha1/api_v1alpha1.pb.go -index 82b0440900..40487270ec 100755 ---- a/pkg/hooks/v1alpha1/api_v1alpha1.pb.go -+++ b/pkg/hooks/v1alpha1/api_v1alpha1.pb.go -@@ -15,15 +15,12 @@ It has these top-level messages: - */ - package v1alpha1 - --import ( -- fmt "fmt" -- -- proto "github.com/golang/protobuf/proto" -- -- math "math" -+import proto "github.com/golang/protobuf/proto" -+import fmt "fmt" -+import math "math" - -+import ( - context "golang.org/x/net/context" -- - grpc "google.golang.org/grpc" - ) - -diff --git a/pkg/hooks/v1alpha2/api_v1alpha2.pb.go b/pkg/hooks/v1alpha2/api_v1alpha2.pb.go -index a7184d4203..adad2a72b6 100755 ---- a/pkg/hooks/v1alpha2/api_v1alpha2.pb.go -+++ b/pkg/hooks/v1alpha2/api_v1alpha2.pb.go -@@ -17,15 +17,12 @@ It has these top-level messages: - */ - package v1alpha2 - --import ( -- fmt "fmt" -- -- proto "github.com/golang/protobuf/proto" -- -- math "math" -+import proto "github.com/golang/protobuf/proto" -+import fmt "fmt" -+import math "math" - -+import ( - context "golang.org/x/net/context" -- - grpc "google.golang.org/grpc" - ) - -diff --git a/pkg/hooks/v1alpha3/api_v1alpha3.pb.go b/pkg/hooks/v1alpha3/api_v1alpha3.pb.go -index 628fb81562..f4776959b3 100644 ---- a/pkg/hooks/v1alpha3/api_v1alpha3.pb.go -+++ b/pkg/hooks/v1alpha3/api_v1alpha3.pb.go -@@ -19,15 +19,12 @@ It has these top-level messages: - */ - package v1alpha3 - --import ( -- fmt "fmt" -- -- proto "github.com/golang/protobuf/proto" -- -- math "math" -+import proto "github.com/golang/protobuf/proto" -+import fmt "fmt" -+import math "math" - -+import ( - context "golang.org/x/net/context" -- - grpc "google.golang.org/grpc" - ) - -diff --git a/pkg/util/checksum/checksum.go b/pkg/util/checksum/checksum.go -new file mode 100644 -index 0000000000..cb05a968b9 ---- /dev/null -+++ b/pkg/util/checksum/checksum.go -@@ -0,0 +1,24 @@ -+package checksum -+ -+import ( -+ "crypto/sha256" -+ "encoding/hex" -+ -+ "k8s.io/apimachinery/pkg/util/json" -+ virtv1 "kubevirt.io/api/core/v1" -+) -+ -+func FromVMISpec(vmiSpec *virtv1.VirtualMachineInstanceSpec) (string, error) { -+ data, err := json.Marshal(vmiSpec) -+ if err != nil { -+ return "", err -+ } -+ return FromBytes(data), nil -+} -+ -+func FromBytes(data []byte) string { -+ hasher := sha256.New() -+ hasher.Write(data) -+ sum := hasher.Sum(nil) -+ return hex.EncodeToString(sum) -+} -diff --git a/pkg/util/syncobject/syncobject.go b/pkg/util/syncobject/syncobject.go -new file mode 100644 -index 0000000000..0e53df4907 ---- /dev/null -+++ b/pkg/util/syncobject/syncobject.go -@@ -0,0 +1,29 @@ -+package syncobject -+ -+import "sync" -+ -+type SyncObject[T any] interface { -+ Get() T -+ Set(value T) -+} -+ -+func NewSyncObject[T any]() SyncObject[T] { -+ return &defaultSyncObject[T]{} -+} -+ -+type defaultSyncObject[T any] struct { -+ value T -+ mu sync.RWMutex -+} -+ -+func (d *defaultSyncObject[T]) Get() T { -+ d.mu.RLock() -+ defer d.mu.RUnlock() -+ return d.value -+} -+ -+func (d *defaultSyncObject[T]) Set(value T) { -+ d.mu.Lock() -+ defer d.mu.Unlock() -+ d.value = value -+} -diff --git a/pkg/virt-handler/checksum-controller/checksum-controller.go b/pkg/virt-handler/checksum-controller/checksum-controller.go -new file mode 100644 -index 0000000000..affcf99ae5 ---- /dev/null -+++ b/pkg/virt-handler/checksum-controller/checksum-controller.go -@@ -0,0 +1,208 @@ -+package checksum_controller -+ -+import ( -+ "context" -+ "fmt" -+ "strings" -+ "sync" -+ "time" -+ -+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -+ "k8s.io/apimachinery/pkg/types" -+ "k8s.io/apimachinery/pkg/util/wait" -+ "k8s.io/client-go/tools/cache" -+ "k8s.io/client-go/util/workqueue" -+ v1 "kubevirt.io/api/core/v1" -+ "kubevirt.io/client-go/kubecli" -+ "kubevirt.io/client-go/log" -+ -+ "kubevirt.io/kubevirt/pkg/apimachinery/patch" -+ "kubevirt.io/kubevirt/pkg/util/checksum" -+) -+ -+const ( -+ controllerName = "ChecksumController" -+ AnnotationChecksum = "integrity.virtualization.deckhouse.io/core-spec-checksum" -+ AnnotationChecksumApplied = "integrity.virtualization.deckhouse.io/core-spec-checksum-applied" -+) -+ -+type VMIChecksumGetter interface { -+ GetAppliedVMIChecksum() (string, error) -+} -+ -+func NewController(vmiSourceInformer cache.SharedIndexInformer, clientset kubecli.KubevirtClient) *Controller { -+ queue := workqueue.NewRateLimitingQueueWithConfig( -+ workqueue.DefaultControllerRateLimiter(), -+ workqueue.RateLimitingQueueConfig{Name: controllerName}) -+ -+ return &Controller{ -+ vmiSourceInformer: vmiSourceInformer, -+ clientset: clientset, -+ queue: queue, -+ log: log.DefaultLogger().With("controller", controllerName), -+ objects: make(map[types.NamespacedName]VMIControl), -+ } -+} -+ -+type Controller struct { -+ vmiSourceInformer cache.SharedIndexInformer -+ clientset kubecli.KubevirtClient -+ queue workqueue.RateLimitingInterface -+ -+ log *log.FilteredLogger -+ -+ objects map[types.NamespacedName]VMIControl -+ mu sync.RWMutex -+} -+ -+func (c *Controller) Run(stopCh <-chan struct{}) { -+ defer c.queue.ShutDown() -+ c.log.Info("Starting checksum controller") -+ -+ go wait.Until(func() { -+ for key := range c.objects { -+ c.queue.Add(key) -+ } -+ }, time.Minute, stopCh) -+ -+ wait.Until(c.runWorker, time.Second, stopCh) -+} -+ -+func (c *Controller) runWorker() { -+ for c.Execute() { -+ } -+} -+ -+func (c *Controller) Execute() bool { -+ key, quit := c.queue.Get() -+ if quit { -+ return false -+ } -+ defer c.queue.Done(key) -+ if err := c.execute(key.(types.NamespacedName)); err != nil { -+ c.log.Reason(err).Infof("re-enqueuing VirtualMachineInstance %v", key) -+ c.queue.AddRateLimited(key) -+ } else { -+ c.log.V(4).Infof("processed VirtualMachineInstance %v", key) -+ c.queue.Forget(key) -+ } -+ return true -+} -+ -+func (c *Controller) execute(key types.NamespacedName) error { -+ vmi, exist, err := c.getVMIFromCache(key) -+ if err != nil { -+ return fmt.Errorf("could not get VirtualMachine instance %v: %w", key, err) -+ } -+ if !exist || !vmi.DeletionTimestamp.IsZero() { -+ c.delete(key) -+ return nil -+ } -+ control, found := c.get(key) -+ if !found { -+ return nil -+ } -+ -+ sum, err := control.checksumGetter.GetAppliedVMIChecksum() -+ if err != nil { -+ return fmt.Errorf("could not get checksum for VirtualMachine instance %v: %w", key, err) -+ } -+ err = c.patchVMI(vmi, control.Checksum, sum) -+ if err != nil { -+ return fmt.Errorf("could not patch VirtualMachine instance %v: %w", key, err) -+ } -+ -+ return nil -+} -+ -+func (c *Controller) getVMIFromCache(key types.NamespacedName) (vmi *v1.VirtualMachineInstance, exists bool, err error) { -+ obj, exists, err := c.vmiSourceInformer.GetStore().GetByKey(key.String()) -+ if err != nil { -+ return nil, false, err -+ } -+ -+ if exists { -+ vmi = obj.(*v1.VirtualMachineInstance).DeepCopy() -+ } -+ return vmi, exists, nil -+} -+ -+func (c *Controller) patchVMI(vmi *v1.VirtualMachineInstance, handlerSum, launcherSum string) error { -+ patchset := patch.New() -+ -+ addPatch := func(anno, needValue string) { -+ value, exist := vmi.Annotations[anno] -+ path := fmt.Sprintf("/metadata/annotations/%s", EscapeJSONPointer(anno)) -+ -+ if !exist { -+ patchset.AddOption(patch.WithAdd(path, needValue)) -+ } else if value != needValue { -+ patchset.AddOption(patch.WithReplace(path, needValue)) -+ } -+ } -+ -+ addPatch(AnnotationChecksum, handlerSum) -+ addPatch(AnnotationChecksumApplied, launcherSum) -+ -+ if patchset.IsEmpty() { -+ return nil -+ } -+ -+ patchBytes, err := patchset.GeneratePayload() -+ if err != nil { -+ return err -+ } -+ _, err = c.clientset.VirtualMachineInstance(vmi.Namespace).Patch(context.Background(), vmi.Name, types.JSONPatchType, patchBytes, metav1.PatchOptions{}) -+ -+ return err -+} -+ -+func (c *Controller) Set(control VMIControl) { -+ c.mu.Lock() -+ defer c.mu.Unlock() -+ c.objects[control.NamespacedName] = control -+} -+ -+func (c *Controller) delete(key types.NamespacedName) { -+ c.mu.Lock() -+ defer c.mu.Unlock() -+ delete(c.objects, key) -+} -+ -+func (c *Controller) get(key types.NamespacedName) (VMIControl, bool) { -+ c.mu.RLock() -+ defer c.mu.RUnlock() -+ control, ok := c.objects[key] -+ return control, ok -+} -+ -+func NewVMIControl(vmi *v1.VirtualMachineInstance, checksumGetter VMIChecksumGetter) (VMIControl, error) { -+ if vmi == nil { -+ return VMIControl{}, fmt.Errorf("vmi is nil") -+ } -+ sum, err := checksum.FromVMISpec(&vmi.Spec) -+ if err != nil { -+ return VMIControl{}, err -+ } -+ return VMIControl{ -+ NamespacedName: types.NamespacedName{ -+ Name: vmi.Name, -+ Namespace: vmi.Namespace, -+ }, -+ UID: vmi.UID, -+ Checksum: sum, -+ checksumGetter: checksumGetter, -+ }, nil -+} -+ -+type VMIControl struct { -+ NamespacedName types.NamespacedName -+ UID types.UID -+ Checksum string -+ -+ checksumGetter VMIChecksumGetter -+} -+ -+func EscapeJSONPointer(path string) string { -+ return strings.ReplaceAll(path, "/", "~1") -+} -diff --git a/pkg/virt-handler/cmd-client/client.go b/pkg/virt-handler/cmd-client/client.go -index d0d1ea0378..68213c6456 100644 ---- a/pkg/virt-handler/cmd-client/client.go -+++ b/pkg/virt-handler/cmd-client/client.go -@@ -113,6 +113,7 @@ type LauncherClient interface { - GetLaunchMeasurement(*v1.VirtualMachineInstance) (*v1.SEVMeasurementInfo, error) - InjectLaunchSecret(*v1.VirtualMachineInstance, *v1.SEVSecretOptions) error - SyncVirtualMachineMemory(vmi *v1.VirtualMachineInstance, options *cmdv1.VirtualMachineOptions) error -+ GetAppliedVMIChecksum() (string, error) - } - - type VirtLauncherClient struct { -@@ -859,3 +860,25 @@ func (c *VirtLauncherClient) InjectLaunchSecret(vmi *v1.VirtualMachineInstance, - func (c *VirtLauncherClient) SyncVirtualMachineMemory(vmi *v1.VirtualMachineInstance, options *cmdv1.VirtualMachineOptions) error { - return c.genericSendVMICmd("SyncVirtualMachineMemory", c.v1client.SyncVirtualMachineMemory, vmi, options) - } -+ -+func (c *VirtLauncherClient) GetAppliedVMIChecksum() (string, error) { -+ request := &cmdv1.EmptyRequest{} -+ ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) -+ defer cancel() -+ -+ checksumResponse, err := c.v1client.GetAppliedVMIChecksum(ctx, request) -+ var response *cmdv1.Response -+ if checksumResponse != nil { -+ response = checksumResponse.Response -+ } -+ if err = handleError(err, "GetAppliedVMIChecksum", response); err != nil { -+ return "", err -+ } -+ -+ if checksumResponse != nil { -+ return checksumResponse.Checksum, nil -+ } -+ -+ log.Log.Reason(err).Error("error getting the checksum") -+ return "", errors.New("error getting the checksum") -+} -diff --git a/pkg/virt-handler/vm.go b/pkg/virt-handler/vm.go -index ce689368a8..0e8825cfd2 100644 ---- a/pkg/virt-handler/vm.go -+++ b/pkg/virt-handler/vm.go -@@ -37,6 +37,7 @@ import ( - "time" - - backendstorage "kubevirt.io/kubevirt/pkg/storage/backend-storage" -+ checksum_controller "kubevirt.io/kubevirt/pkg/virt-handler/checksum-controller" - - cmdv1 "kubevirt.io/kubevirt/pkg/handler-launcher-com/cmd/v1" - pvctypes "kubevirt.io/kubevirt/pkg/storage/types" -@@ -286,10 +287,10 @@ func NewController( - } - - _, err = domainInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{ -- UpdateFunc: c.updateNetworkPriorityFunc, -- }) -+ UpdateFunc: c.updateNetworkPriorityFunc, -+ }) - if err != nil { -- return nil, err -+ return nil, err - } - - c.launcherClients = virtcache.LauncherClientInfoByVMI{} -@@ -322,6 +323,8 @@ func NewController( - clientset.CoreV1()) - c.heartBeat = heartbeat.NewHeartBeat(clientset.CoreV1(), c.deviceManagerController, clusterConfig, host) - -+ c.checksumCtrl = checksum_controller.NewController(c.vmiSourceInformer, c.clientset) -+ - return c, nil - } - -@@ -360,7 +363,9 @@ type VirtualMachineController struct { - ioErrorRetryManager *FailRetryManager - - hotplugContainerDiskMounter container_disk.HotplugMounter -- nam *migrations.NetworkAccessibilityManager -+ nam *migrations.NetworkAccessibilityManager -+ -+ checksumCtrl *checksum_controller.Controller - } - - type virtLauncherCriticalSecurebootError struct { -@@ -1732,6 +1737,8 @@ func (c *VirtualMachineController) Run(threadiness int, stopCh chan struct{}) { - go wait.Until(c.runWorker, time.Second, stopCh) - } - -+ go c.checksumCtrl.Run(stopCh) -+ - <-stopCh - <-heartBeatDone - log.Log.Info("Stopping virt-handler controller.") -@@ -3267,7 +3274,7 @@ func (d *VirtualMachineController) vmUpdateHelperDefault(origVMI *v1.VirtualMach - options := virtualMachineOptions(smbios, period, preallocatedVolumes, d.capabilities, disksInfo, d.clusterConfig) - options.InterfaceDomainAttachment = domainspec.DomainAttachmentByInterfaceName(vmi.Spec.Domain.Devices.Interfaces, d.clusterConfig.GetNetworkBindings()) - -- err = client.SyncVirtualMachine(vmi, options) -+ err = d.SyncVirtualMachine(client, vmi, options) - if err != nil { - isSecbootError := strings.Contains(err.Error(), "EFI OVMF rom missing") - if isSecbootError { -@@ -3350,7 +3357,7 @@ func (d *VirtualMachineController) hotplugSriovInterfacesCommand(vmi *v1.Virtual - } - - log.Log.V(3).Object(vmi).Info("sending hot-plug host-devices command") -- if err := client.HotplugHostDevices(vmi); err != nil { -+ if err := d.HotplugHostDevices(client, vmi); err != nil { - return fmt.Errorf("%s: %v", errMsgPrefix, err) - } - -@@ -3709,7 +3716,7 @@ func (d *VirtualMachineController) hotplugCPU(vmi *v1.VirtualMachineInstance, cl - nil, - d.clusterConfig) - -- if err := client.SyncVirtualMachineCPUs(vmi, options); err != nil { -+ if err := d.SyncVirtualMachineCPU(client, vmi, options); err != nil { - return err - } - -@@ -3757,7 +3764,7 @@ func (d *VirtualMachineController) hotplugMemory(vmi *v1.VirtualMachineInstance, - - options := virtualMachineOptions(nil, 0, nil, d.capabilities, nil, d.clusterConfig) - -- if err := client.SyncVirtualMachineMemory(vmi, options); err != nil { -+ if err := d.SyncVirtualMachineMemory(client, vmi, options); err != nil { - // mark hotplug as failed - vmiConditions.UpdateCondition(vmi, &v1.VirtualMachineInstanceCondition{ - Type: v1.VirtualMachineInstanceMemoryChange, -@@ -3858,3 +3865,51 @@ func (d *VirtualMachineController) updateNetworkPriorityFunc(_, new interface{}) - return - } - } -+ -+func (d *VirtualMachineController) SyncVirtualMachine(client cmdclient.LauncherClient, vmi *v1.VirtualMachineInstance, options *cmdv1.VirtualMachineOptions) error { -+ control, err := checksum_controller.NewVMIControl(vmi, client) -+ if err != nil { -+ return err -+ } -+ if err = client.SyncVirtualMachine(vmi, options); err != nil { -+ return err -+ } -+ d.checksumCtrl.Set(control) -+ return nil -+} -+ -+func (d *VirtualMachineController) SyncVirtualMachineCPU(client cmdclient.LauncherClient, vmi *v1.VirtualMachineInstance, options *cmdv1.VirtualMachineOptions) error { -+ control, err := checksum_controller.NewVMIControl(vmi, client) -+ if err != nil { -+ return err -+ } -+ if err = client.SyncVirtualMachineCPUs(vmi, options); err != nil { -+ return err -+ } -+ d.checksumCtrl.Set(control) -+ return nil -+} -+ -+func (d *VirtualMachineController) SyncVirtualMachineMemory(client cmdclient.LauncherClient, vmi *v1.VirtualMachineInstance, options *cmdv1.VirtualMachineOptions) error { -+ control, err := checksum_controller.NewVMIControl(vmi, client) -+ if err != nil { -+ return err -+ } -+ if err = client.SyncVirtualMachineMemory(vmi, options); err != nil { -+ return err -+ } -+ d.checksumCtrl.Set(control) -+ return nil -+} -+ -+func (d *VirtualMachineController) HotplugHostDevices(client cmdclient.LauncherClient, vmi *v1.VirtualMachineInstance) error { -+ control, err := checksum_controller.NewVMIControl(vmi, client) -+ if err != nil { -+ return err -+ } -+ if err = client.HotplugHostDevices(vmi); err != nil { -+ return err -+ } -+ d.checksumCtrl.Set(control) -+ return nil -+} -diff --git a/pkg/virt-launcher/virtwrap/cmd-server/server.go b/pkg/virt-launcher/virtwrap/cmd-server/server.go -index 9815b402b9..2be5af2eb3 100644 ---- a/pkg/virt-launcher/virtwrap/cmd-server/server.go -+++ b/pkg/virt-launcher/virtwrap/cmd-server/server.go -@@ -741,6 +741,18 @@ func (l *Launcher) SyncVirtualMachineMemory(_ context.Context, request *cmdv1.VM - return response, nil - } - -+func (l *Launcher) GetAppliedVMIChecksum(_ context.Context, _ *cmdv1.EmptyRequest) (*cmdv1.VMIChecksumResponse, error) { -+ checksum := l.domainManager.GetAppliedVMIChecksum() -+ log.Log.V(5).Infof("GetAppliedVMIChecksum: %q", checksum) -+ response := &cmdv1.VMIChecksumResponse{ -+ Checksum: checksum, -+ Response: &cmdv1.Response{ -+ Success: true, -+ }, -+ } -+ return response, nil -+} -+ - func ReceivedEarlyExitSignal() bool { - _, earlyExit := os.LookupEnv(receivedEarlyExitSignalEnvVar) - return earlyExit -diff --git a/pkg/virt-launcher/virtwrap/manager.go b/pkg/virt-launcher/virtwrap/manager.go -index cddee4f199..6744cb2913 100644 ---- a/pkg/virt-launcher/virtwrap/manager.go -+++ b/pkg/virt-launcher/virtwrap/manager.go -@@ -42,6 +42,8 @@ import ( - "sync" - "time" - -+ "kubevirt.io/kubevirt/pkg/util/checksum" -+ "kubevirt.io/kubevirt/pkg/util/syncobject" - virtcache "kubevirt.io/kubevirt/tools/cache" - - "k8s.io/utils/pointer" -@@ -145,6 +147,7 @@ type DomainManager interface { - GetLaunchMeasurement(*v1.VirtualMachineInstance) (*v1.SEVMeasurementInfo, error) - InjectLaunchSecret(*v1.VirtualMachineInstance, *v1.SEVSecretOptions) error - UpdateGuestMemory(vmi *v1.VirtualMachineInstance) error -+ GetAppliedVMIChecksum() string - } - - type LibvirtDomainManager struct { -@@ -176,6 +179,8 @@ type LibvirtDomainManager struct { - - metadataCache *metadata.Cache - domainStatsCache *virtcache.TimeDefinedCache[*stats.DomainStats] -+ -+ checksum syncobject.SyncObject[string] - } - - type pausedVMIs struct { -@@ -222,6 +227,8 @@ func newLibvirtDomainManager(connection cli.Connection, virtShareDir, ephemeralD - cancelSafetyUnfreezeChan: make(chan struct{}), - migrateInfoStats: &stats.DomainJobInfo{}, - metadataCache: metadataCache, -+ -+ checksum: syncobject.NewSyncObject[string](), - } - - manager.hotplugHostDevicesInProgress = make(chan struct{}, maxConcurrentHotplugHostDevices) -@@ -285,6 +292,11 @@ func (l *LibvirtDomainManager) UpdateGuestMemory(vmi *v1.VirtualMachineInstance) - l.domainModifyLock.Lock() - defer l.domainModifyLock.Unlock() - -+ var origSpec *v1.VirtualMachineInstanceSpec -+ if vmi != nil { -+ origSpec = vmi.Spec.DeepCopy() -+ } -+ - const errMsgPrefix = "failed to update Guest Memory" - - domainName := api.VMINamespaceKeyFunc(vmi) -@@ -332,6 +344,12 @@ func (l *LibvirtDomainManager) UpdateGuestMemory(vmi *v1.VirtualMachineInstance) - } - } - -+ sum, err := checksum.FromVMISpec(origSpec) -+ if err != nil { -+ return fmt.Errorf("failed to calculate checksum of VMI spec: %w", err) -+ } -+ l.checksum.Set(sum) -+ - log.Log.V(2).Infof("hotplugging guest memory to %v", vmi.Spec.Domain.Memory.Guest.Value()) - return nil - } -@@ -449,6 +467,11 @@ func (l *LibvirtDomainManager) UpdateVCPUs(vmi *v1.VirtualMachineInstance, optio - l.domainModifyLock.Lock() - defer l.domainModifyLock.Unlock() - -+ var origSpec *v1.VirtualMachineInstanceSpec -+ if vmi != nil { -+ origSpec = vmi.Spec.DeepCopy() -+ } -+ - const errMsgPrefix = "failed to update vCPUs" - - domainName := api.VMINamespaceKeyFunc(vmi) -@@ -528,8 +551,14 @@ func (l *LibvirtDomainManager) UpdateVCPUs(vmi *v1.VirtualMachineInstance, optio - return fmt.Errorf("%s: %v", errMsgPrefix, err) - } - } -+ } - -+ sum, err := checksum.FromVMISpec(origSpec) -+ if err != nil { -+ return fmt.Errorf("failed to calculate checksum of VMI spec: %w", err) - } -+ l.checksum.Set(sum) -+ - return nil - } - -@@ -555,9 +584,20 @@ func (l *LibvirtDomainManager) HotplugHostDevices(vmi *v1.VirtualMachineInstance - go func() { - defer func() { <-l.hotplugHostDevicesInProgress }() - -+ var origSpec *v1.VirtualMachineInstanceSpec -+ if vmi != nil { -+ origSpec = vmi.Spec.DeepCopy() -+ } - if err := l.hotPlugHostDevices(vmi); err != nil { - log.Log.Object(vmi).Error(err.Error()) - } -+ -+ sum, err := checksum.FromVMISpec(origSpec) -+ if err != nil { -+ log.Log.Object(vmi).Errorf("Failed to calculate checksum: %v", err) -+ } -+ l.checksum.Set(sum) -+ - }() - return nil - } -@@ -1087,6 +1127,11 @@ func (l *LibvirtDomainManager) SyncVMI(vmi *v1.VirtualMachineInstance, allowEmul - l.domainModifyLock.Lock() - defer l.domainModifyLock.Unlock() - -+ var originalSpec *v1.VirtualMachineInstanceSpec -+ if vmi != nil { -+ originalSpec = vmi.Spec.DeepCopy() -+ } -+ - logger := log.Log.Object(vmi) - - domain := &api.Domain{} -@@ -1147,6 +1192,13 @@ func (l *LibvirtDomainManager) SyncVMI(vmi *v1.VirtualMachineInstance, allowEmul - return nil, err - } - -+ // Set CHECKSUM VMI SPEC -+ sum, err := checksum.FromVMISpec(originalSpec) -+ if err != nil { -+ return nil, fmt.Errorf("failed to calculate checksum of VMI spec: %w", err) -+ } -+ l.checksum.Set(sum) -+ - // TODO: check if VirtualMachineInstance Spec and Domain Spec are equal or if we have to sync - return oldSpec, nil - } -@@ -2334,3 +2386,7 @@ func getDomainCreateFlags(vmi *v1.VirtualMachineInstance) libvirt.DomainCreateFl - } - return flags - } -+ -+func (l *LibvirtDomainManager) GetAppliedVMIChecksum() string { -+ return l.checksum.Get() -+} -diff --git a/pkg/virt-operator/resource/generate/rbac/handler.go b/pkg/virt-operator/resource/generate/rbac/handler.go -index 2640f61826..5d9a7b6279 100644 ---- a/pkg/virt-operator/resource/generate/rbac/handler.go -+++ b/pkg/virt-operator/resource/generate/rbac/handler.go -@@ -78,7 +78,7 @@ func newHandlerClusterRole() *rbacv1.ClusterRole { - "virtualmachineinstances", - }, - Verbs: []string{ -- "update", "list", "watch", -+ "update", "list", "watch", "patch", - }, - }, - { -diff --git a/pkg/vsock/system/v1/system.pb.go b/pkg/vsock/system/v1/system.pb.go -index 6f743628c7..2c47c64162 100644 ---- a/pkg/vsock/system/v1/system.pb.go -+++ b/pkg/vsock/system/v1/system.pb.go -@@ -15,15 +15,12 @@ It has these top-level messages: - */ - package v1 - --import ( -- fmt "fmt" -- -- proto "github.com/golang/protobuf/proto" -- -- math "math" -+import proto "github.com/golang/protobuf/proto" -+import fmt "fmt" -+import math "math" - -+import ( - context "golang.org/x/net/context" -- - grpc "google.golang.org/grpc" - ) - diff --git a/images/virt-artifact/patches/040-set-reboot-policy.patch b/images/virt-artifact/patches/040-set-reboot-policy.patch deleted file mode 100644 index 7ebd5bcea1..0000000000 --- a/images/virt-artifact/patches/040-set-reboot-policy.patch +++ /dev/null @@ -1,207 +0,0 @@ -diff --git a/pkg/virt-launcher/notify-client/client.go b/pkg/virt-launcher/notify-client/client.go -index 5da5f68103..a1e200de35 100644 ---- a/pkg/virt-launcher/notify-client/client.go -+++ b/pkg/virt-launcher/notify-client/client.go -@@ -3,6 +3,7 @@ package eventsclient - import ( - "context" - "fmt" -+ "os" - "path/filepath" - "sync" - "time" -@@ -528,6 +529,39 @@ func (n *Notifier) StartDomainNotifier( - } - } - -+ domainQemuMonitorEventShutdownCallback := func(_ *libvirt.Connect, _ *libvirt.Domain, event *libvirt.DomainQemuMonitorEvent) { -+ -+ type Result struct { -+ Event string `json:"event"` -+ Details string `json:"details"` -+ } -+ -+ log.Log.Infof("Domain Qemu Monitor Shutdown event received") -+ -+ f, err := os.OpenFile("/dev/termination-log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) -+ if err != nil { -+ log.Log.Reason(err).Error("Failed to open /dev/termination-log") -+ return -+ } -+ defer f.Close() -+ -+ r := Result{ -+ Event: event.Event, -+ Details: event.Details, -+ } -+ -+ b, err := json.Marshal(r) -+ if err != nil { -+ log.Log.Reason(err).Errorf("Failed to marshal result to JSON. event: %s, details: %s", event.Event, event.Details) -+ return -+ } -+ b = append(b, '\n') -+ -+ if _, err = f.Write(b); err != nil { -+ log.Log.Reason(err).Error("Failed to write to termination-log") -+ } -+ } -+ - err := domainConn.DomainEventLifecycleRegister(domainEventLifecycleCallback) - if err != nil { - log.Log.Reason(err).Errorf("failed to register event callback with libvirt") -@@ -567,6 +601,15 @@ func (n *Notifier) StartDomainNotifier( - log.Log.Reason(err).Errorf("failed to register event callback with libvirt") - return err - } -+ for _, event := range []string{ -+ "SHUTDOWN", -+ } { -+ err = domainConn.DomainQemuMonitorEventRegister(event, domainQemuMonitorEventShutdownCallback) -+ if err != nil { -+ log.Log.Reason(err).Errorf("failed to register event callback with libvirt") -+ return err -+ } -+ } - - log.Log.Infof("Registered libvirt event notify callback") - return nil -diff --git a/pkg/virt-launcher/virtwrap/cli/libvirt.go b/pkg/virt-launcher/virtwrap/cli/libvirt.go -index 2ae00bc802..9991862746 100644 ---- a/pkg/virt-launcher/virtwrap/cli/libvirt.go -+++ b/pkg/virt-launcher/virtwrap/cli/libvirt.go -@@ -65,6 +65,9 @@ type Connection interface { - GetDomainStats(statsTypes libvirt.DomainStatsTypes, l *stats.DomainJobInfo, flags libvirt.ConnectGetAllDomainStatsFlags) ([]*stats.DomainStats, error) - GetQemuVersion() (string, error) - GetSEVInfo() (*api.SEVNodeParameters, error) -+ -+ DomainQemuMonitorEventRegister(event string, callback libvirt.DomainQemuMonitorEventCallback) (err error) -+ QemuMonitorCommand(command string, domainName string) (string, error) - } - - type Stream interface { -@@ -92,6 +95,7 @@ type LibvirtConnection struct { - domainEventMigrationIterationCallbacks []libvirt.DomainEventMigrationIterationCallback - agentEventCallbacks []libvirt.DomainEventAgentLifecycleCallback - domainDeviceMemoryDeviceSizeChangeCallbacks []libvirt.DomainEventMemoryDeviceSizeChangeCallback -+ domainQemuMonitorEventCallbacks []qemuMonitorEventRegister - } - - func (s *VirStream) Write(p []byte) (n int, err error) { -@@ -195,6 +199,29 @@ func (l *LibvirtConnection) DomainEventMemoryDeviceSizeChangeRegister(callback l - return - } - -+type qemuMonitorEventRegister struct { -+ event string -+ callback libvirt.DomainQemuMonitorEventCallback -+} -+ -+func (l *LibvirtConnection) DomainQemuMonitorEventRegister(event string, callback libvirt.DomainQemuMonitorEventCallback) (err error) { -+ if err = l.reconnectIfNecessary(); err != nil { -+ return -+ } -+ l.domainQemuMonitorEventCallbacks = append(l.domainQemuMonitorEventCallbacks, qemuMonitorEventRegister{ -+ event: event, -+ callback: callback, -+ }) -+ err = l.domainQemuMonitorEventRegister(event, callback) -+ l.checkConnectionLost(err) -+ return -+} -+ -+func (l *LibvirtConnection) domainQemuMonitorEventRegister(event string, callback libvirt.DomainQemuMonitorEventCallback) (err error) { -+ _, err = l.Connect.DomainQemuMonitorEventRegister(nil, event, callback, libvirt.CONNECT_DOMAIN_QEMU_MONITOR_EVENT_REGISTER_NOCASE) -+ return -+} -+ - func (l *LibvirtConnection) DomainEventDeregister(registrationID int) error { - return l.Connect.DomainEventDeregister(registrationID) - } -@@ -252,6 +279,19 @@ func (l *LibvirtConnection) QemuAgentCommand(command string, domainName string) - return result, err - } - -+func (l *LibvirtConnection) QemuMonitorCommand(command string, domainName string) (string, error) { -+ if err := l.reconnectIfNecessary(); err != nil { -+ return "", err -+ } -+ domain, err := l.Connect.LookupDomainByName(domainName) -+ if err != nil { -+ return "", err -+ } -+ defer domain.Free() -+ result, err := domain.QemuMonitorCommand(command, libvirt.DOMAIN_QEMU_MONITOR_COMMAND_DEFAULT) -+ return result, err -+} -+ - func (l *LibvirtConnection) GetAllDomainStats(statsTypes libvirt.DomainStatsTypes, flags libvirt.ConnectGetAllDomainStatsFlags) ([]libvirt.DomainStats, error) { - if err := l.reconnectIfNecessary(); err != nil { - return nil, err -@@ -461,6 +501,10 @@ func (l *LibvirtConnection) reconnectIfNecessary() (err error) { - log.Log.Info("Re-registered domain memory device size change callback") - _, err = l.Connect.DomainEventMemoryDeviceSizeChangeRegister(nil, callback) - } -+ for _, reg := range l.domainQemuMonitorEventCallbacks { -+ log.Log.Info("Re-registered domain qemu monitor events callback") -+ err = l.domainQemuMonitorEventRegister(reg.event, reg.callback) -+ } - - log.Log.Error("Re-registered domain and agent callbacks for new connection") - -diff --git a/pkg/virt-launcher/virtwrap/live-migration-target.go b/pkg/virt-launcher/virtwrap/live-migration-target.go -index 8658fcfbc7..ff22f14a40 100644 ---- a/pkg/virt-launcher/virtwrap/live-migration-target.go -+++ b/pkg/virt-launcher/virtwrap/live-migration-target.go -@@ -180,7 +180,6 @@ func (l *LibvirtDomainManager) prepareMigrationTarget( - if err != nil { - return fmt.Errorf("executing custom preStart hooks failed: %v", err) - } -- - if shouldBlockMigrationTargetPreparation(vmi) { - return fmt.Errorf("Blocking preparation of migration target in order to satisfy a functional test condition") - } -diff --git a/pkg/virt-launcher/virtwrap/manager.go b/pkg/virt-launcher/virtwrap/manager.go -index 6744cb2913..c6e675d1b8 100644 ---- a/pkg/virt-launcher/virtwrap/manager.go -+++ b/pkg/virt-launcher/virtwrap/manager.go -@@ -181,6 +181,8 @@ type LibvirtDomainManager struct { - domainStatsCache *virtcache.TimeDefinedCache[*stats.DomainStats] - - checksum syncobject.SyncObject[string] -+ -+ rebootShutdownPolicyWasSet bool - } - - type pausedVMIs struct { -@@ -1178,6 +1180,10 @@ func (l *LibvirtDomainManager) SyncVMI(vmi *v1.VirtualMachineInstance, allowEmul - logger.Info("Domain unpaused.") - } - -+ if err := l.setRebootShutdownPolicy(dom); err != nil { -+ return nil, fmt.Errorf("failed to set reboot shutdown policy: %v", err) -+ } -+ - oldSpec, err := getDomainSpec(dom) - if err != nil { - logger.Reason(err).Error("Parsing domain XML failed.") -@@ -2390,3 +2396,19 @@ func getDomainCreateFlags(vmi *v1.VirtualMachineInstance) libvirt.DomainCreateFl - func (l *LibvirtDomainManager) GetAppliedVMIChecksum() string { - return l.checksum.Get() - } -+ -+func (l *LibvirtDomainManager) setRebootShutdownPolicy(dom cli.VirDomain) error { -+ if l.rebootShutdownPolicyWasSet { -+ return nil -+ } -+ name, err := dom.GetName() -+ if err != nil { -+ return err -+ } -+ _, err = l.virConn.QemuMonitorCommand(`{"execute": "set-action", "arguments":{"reboot":"shutdown"}}`, name) -+ if err != nil { -+ return err -+ } -+ l.rebootShutdownPolicyWasSet = true -+ return nil -+} diff --git a/images/virt-artifact/patches/041-rename-node-labeller-virt-launcher-init.patch b/images/virt-artifact/patches/041-rename-node-labeller-virt-launcher-init.patch deleted file mode 100644 index 0ccbbefaaf..0000000000 --- a/images/virt-artifact/patches/041-rename-node-labeller-virt-launcher-init.patch +++ /dev/null @@ -1,34 +0,0 @@ -diff --git a/pkg/virt-operator/resource/generate/components/daemonsets.go b/pkg/virt-operator/resource/generate/components/daemonsets.go -index 8fa14e93b5..93c55c1619 100644 ---- a/pkg/virt-operator/resource/generate/components/daemonsets.go -+++ b/pkg/virt-operator/resource/generate/components/daemonsets.go -@@ -52,7 +52,6 @@ func RenderPrHelperContainer(image string, pullPolicy corev1.PullPolicy) corev1. - } - - func NewHandlerDaemonSet(namespace, repository, imagePrefix, version, launcherVersion, prHelperVersion, sidecarShimVersion, productName, productVersion, productComponent, image, launcherImage, prHelperImage, sidecarShimImage string, pullPolicy corev1.PullPolicy, imagePullSecrets []corev1.LocalObjectReference, migrationNetwork *string, verbosity string, extraEnv map[string]string, enablePrHelper bool) (*appsv1.DaemonSet, error) { -- - deploymentName := VirtHandlerName - imageName := fmt.Sprintf("%s%s", imagePrefix, deploymentName) - env := operatorutil.NewEnvVarMap(extraEnv) -@@ -117,14 +116,10 @@ func NewHandlerDaemonSet(namespace, repository, imagePrefix, version, launcherVe - pod.InitContainers = []corev1.Container{ - { - Command: []string{ -- "/bin/sh", -- "-c", -+ "node-labeller", - }, - Image: launcherImage, - Name: "virt-launcher", -- Args: []string{ -- "node-labeller.sh", -- }, - SecurityContext: &corev1.SecurityContext{ - Privileged: pointer.Bool(true), - }, -@@ -350,5 +345,4 @@ func NewHandlerDaemonSet(namespace, repository, imagePrefix, version, launcherVe - pod.Containers = append(pod.Containers, RenderPrHelperContainer(prHelperImage, pullPolicy)) - } - return daemonset, nil -- - } diff --git a/images/virt-artifact/patches/042-restrict-libvirt-socket-to-qemu.patch b/images/virt-artifact/patches/042-restrict-libvirt-socket-to-qemu.patch deleted file mode 100644 index 67fcd41793..0000000000 --- a/images/virt-artifact/patches/042-restrict-libvirt-socket-to-qemu.patch +++ /dev/null @@ -1,722 +0,0 @@ -diff --git a/pkg/handler-launcher-com/cmd/v1/cmd.pb.go b/pkg/handler-launcher-com/cmd/v1/cmd.pb.go -index 6f41c22374..24fb6984ee 100644 ---- a/pkg/handler-launcher-com/cmd/v1/cmd.pb.go -+++ b/pkg/handler-launcher-com/cmd/v1/cmd.pb.go -@@ -42,6 +42,7 @@ It has these top-level messages: - LaunchMeasurementResponse - InjectLaunchSecretRequest - VMIChecksumResponse -+ MigrationProxyRequest - */ - package v1 - -@@ -65,6 +66,27 @@ var _ = math.Inf - // proto package needs to be updated. - const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package - -+type MigrationProxyAction int32 -+ -+const ( -+ MigrationProxyAction_START MigrationProxyAction = 0 -+ MigrationProxyAction_STOP MigrationProxyAction = 1 -+) -+ -+var MigrationProxyAction_name = map[int32]string{ -+ 0: "START", -+ 1: "STOP", -+} -+var MigrationProxyAction_value = map[string]int32{ -+ "START": 0, -+ "STOP": 1, -+} -+ -+func (x MigrationProxyAction) String() string { -+ return proto.EnumName(MigrationProxyAction_name, int32(x)) -+} -+func (MigrationProxyAction) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } -+ - type QemuVersionResponse struct { - Response *Response `protobuf:"bytes,1,opt,name=response" json:"response,omitempty"` - Version string `protobuf:"bytes,2,opt,name=version" json:"version,omitempty"` -@@ -954,6 +976,22 @@ func (m *VMIChecksumResponse) GetChecksum() string { - return "" - } - -+type MigrationProxyRequest struct { -+ Action MigrationProxyAction `protobuf:"varint,1,opt,name=action,enum=kubevirt.cmd.v1.MigrationProxyAction" json:"action,omitempty"` -+} -+ -+func (m *MigrationProxyRequest) Reset() { *m = MigrationProxyRequest{} } -+func (m *MigrationProxyRequest) String() string { return proto.CompactTextString(m) } -+func (*MigrationProxyRequest) ProtoMessage() {} -+func (*MigrationProxyRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{32} } -+ -+func (m *MigrationProxyRequest) GetAction() MigrationProxyAction { -+ if m != nil { -+ return m.Action -+ } -+ return MigrationProxyAction_START -+} -+ - func init() { - proto.RegisterType((*QemuVersionResponse)(nil), "kubevirt.cmd.v1.QemuVersionResponse") - proto.RegisterType((*VMI)(nil), "kubevirt.cmd.v1.VMI") -@@ -987,6 +1025,8 @@ func init() { - proto.RegisterType((*LaunchMeasurementResponse)(nil), "kubevirt.cmd.v1.LaunchMeasurementResponse") - proto.RegisterType((*InjectLaunchSecretRequest)(nil), "kubevirt.cmd.v1.InjectLaunchSecretRequest") - proto.RegisterType((*VMIChecksumResponse)(nil), "kubevirt.cmd.v1.VMIChecksumResponse") -+ proto.RegisterType((*MigrationProxyRequest)(nil), "kubevirt.cmd.v1.MigrationProxyRequest") -+ proto.RegisterEnum("kubevirt.cmd.v1.MigrationProxyAction", MigrationProxyAction_name, MigrationProxyAction_value) - } - - // Reference imports to suppress errors if they are not otherwise used. -@@ -1031,6 +1071,7 @@ type CmdClient interface { - GetLaunchMeasurement(ctx context.Context, in *VMIRequest, opts ...grpc.CallOption) (*LaunchMeasurementResponse, error) - InjectLaunchSecret(ctx context.Context, in *InjectLaunchSecretRequest, opts ...grpc.CallOption) (*Response, error) - GetAppliedVMIChecksum(ctx context.Context, in *EmptyRequest, opts ...grpc.CallOption) (*VMIChecksumResponse, error) -+ MigrationProxy(ctx context.Context, in *MigrationProxyRequest, opts ...grpc.CallOption) (*Response, error) - } - - type cmdClient struct { -@@ -1320,6 +1361,15 @@ func (c *cmdClient) GetAppliedVMIChecksum(ctx context.Context, in *EmptyRequest, - return out, nil - } - -+func (c *cmdClient) MigrationProxy(ctx context.Context, in *MigrationProxyRequest, opts ...grpc.CallOption) (*Response, error) { -+ out := new(Response) -+ err := grpc.Invoke(ctx, "/kubevirt.cmd.v1.Cmd/MigrationProxy", in, out, c.cc, opts...) -+ if err != nil { -+ return nil, err -+ } -+ return out, nil -+} -+ - // Server API for Cmd service - - type CmdServer interface { -@@ -1354,6 +1404,7 @@ type CmdServer interface { - GetLaunchMeasurement(context.Context, *VMIRequest) (*LaunchMeasurementResponse, error) - InjectLaunchSecret(context.Context, *InjectLaunchSecretRequest) (*Response, error) - GetAppliedVMIChecksum(context.Context, *EmptyRequest) (*VMIChecksumResponse, error) -+ MigrationProxy(context.Context, *MigrationProxyRequest) (*Response, error) - } - - func RegisterCmdServer(s *grpc.Server, srv CmdServer) { -@@ -1918,6 +1969,24 @@ func _Cmd_GetAppliedVMIChecksum_Handler(srv interface{}, ctx context.Context, de - return interceptor(ctx, in, info, handler) - } - -+func _Cmd_MigrationProxy_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { -+ in := new(MigrationProxyRequest) -+ if err := dec(in); err != nil { -+ return nil, err -+ } -+ if interceptor == nil { -+ return srv.(CmdServer).MigrationProxy(ctx, in) -+ } -+ info := &grpc.UnaryServerInfo{ -+ Server: srv, -+ FullMethod: "/kubevirt.cmd.v1.Cmd/MigrationProxy", -+ } -+ handler := func(ctx context.Context, req interface{}) (interface{}, error) { -+ return srv.(CmdServer).MigrationProxy(ctx, req.(*MigrationProxyRequest)) -+ } -+ return interceptor(ctx, in, info, handler) -+} -+ - var _Cmd_serviceDesc = grpc.ServiceDesc{ - ServiceName: "kubevirt.cmd.v1.Cmd", - HandlerType: (*CmdServer)(nil), -@@ -2046,6 +2115,10 @@ var _Cmd_serviceDesc = grpc.ServiceDesc{ - MethodName: "GetAppliedVMIChecksum", - Handler: _Cmd_GetAppliedVMIChecksum_Handler, - }, -+ { -+ MethodName: "MigrationProxy", -+ Handler: _Cmd_MigrationProxy_Handler, -+ }, - }, - Streams: []grpc.StreamDesc{}, - Metadata: "pkg/handler-launcher-com/cmd/v1/cmd.proto", -@@ -2054,121 +2127,125 @@ var _Cmd_serviceDesc = grpc.ServiceDesc{ - func init() { proto.RegisterFile("pkg/handler-launcher-com/cmd/v1/cmd.proto", fileDescriptor0) } - - var fileDescriptor0 = []byte{ -- // 1843 bytes of a gzipped FileDescriptorProto -- 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x59, 0x5f, 0x73, 0xdb, 0xc6, -- 0x11, 0x17, 0x45, 0x4a, 0x26, 0x57, 0x7f, 0x12, 0x9f, 0xfe, 0x04, 0x52, 0x6b, 0x5b, 0xc5, 0x74, -- 0x3c, 0x4a, 0x27, 0x91, 0x6a, 0xc7, 0xc9, 0x74, 0x3c, 0x9d, 0x8c, 0x2d, 0x8a, 0x52, 0x94, 0x98, -- 0x36, 0x03, 0x4a, 0xf2, 0x34, 0x6d, 0x9a, 0x39, 0x01, 0x27, 0xf2, 0x2a, 0xe0, 0x0e, 0xc1, 0x1d, -- 0x58, 0x33, 0x4f, 0x9d, 0x49, 0xa7, 0x0f, 0x9d, 0xe9, 0xe7, 0x6b, 0x9f, 0xfa, 0x2d, 0xfa, 0xde, -- 0xb9, 0xc3, 0x81, 0x02, 0x09, 0x40, 0xb2, 0x86, 0x7c, 0x22, 0xf6, 0x6e, 0xf7, 0xb7, 0x7b, 0x77, -- 0xbb, 0x7b, 0x3f, 0x80, 0xf0, 0x71, 0x78, 0xd5, 0xdb, 0xef, 0x63, 0xe6, 0xf9, 0x24, 0xfa, 0xd4, -- 0xc7, 0x31, 0x73, 0xfb, 0x24, 0xfa, 0xd4, 0xe5, 0xc1, 0xbe, 0x1b, 0x78, 0xfb, 0x83, 0x27, 0xea, -- 0x67, 0x2f, 0x8c, 0xb8, 0xe4, 0xe8, 0x83, 0xab, 0xf8, 0x82, 0x0c, 0x68, 0x24, 0xf7, 0xd4, 0xd8, -- 0xe0, 0x89, 0x7d, 0x09, 0x6b, 0xdf, 0x92, 0x20, 0x3e, 0x27, 0x91, 0xa0, 0x9c, 0x39, 0x44, 0x84, -- 0x9c, 0x09, 0x82, 0x3e, 0x87, 0x7a, 0x64, 0x9e, 0xad, 0xca, 0x4e, 0x65, 0x77, 0xe9, 0xe9, 0xd6, -- 0xde, 0x84, 0xe9, 0x5e, 0xaa, 0xec, 0x8c, 0x54, 0x91, 0x05, 0xf7, 0x06, 0x09, 0x92, 0x35, 0xbf, -- 0x53, 0xd9, 0x6d, 0x38, 0xa9, 0x68, 0x3f, 0x82, 0xea, 0x79, 0xfb, 0x44, 0x2b, 0x04, 0xf4, 0x6b, -- 0xc1, 0x99, 0x86, 0x5d, 0x76, 0x52, 0xd1, 0x7e, 0x02, 0xd5, 0x66, 0xe7, 0x0c, 0xad, 0xc2, 0x3c, -- 0xf5, 0xf4, 0xdc, 0x8a, 0x33, 0x4f, 0x3d, 0xb4, 0x0d, 0x75, 0x41, 0x2f, 0x7c, 0xca, 0x7a, 0xc2, -- 0x9a, 0xdf, 0xa9, 0xee, 0xae, 0x38, 0x23, 0xd9, 0xde, 0x87, 0x7b, 0xdd, 0xe4, 0x39, 0x67, 0xb6, -- 0x0e, 0x0b, 0x03, 0xec, 0xc7, 0x44, 0x87, 0x51, 0x73, 0x12, 0xc1, 0x6e, 0xc1, 0x42, 0x07, 0xf7, -- 0x88, 0x50, 0xd3, 0x2e, 0x8f, 0x99, 0xd4, 0x16, 0x35, 0x27, 0x11, 0x10, 0x82, 0x5a, 0xcc, 0xa8, -- 0x34, 0xa1, 0xeb, 0x67, 0x35, 0x26, 0xe8, 0x4f, 0xc4, 0xaa, 0x6a, 0x68, 0xfd, 0x6c, 0x3f, 0x83, -- 0xc5, 0x36, 0x09, 0x78, 0x34, 0x44, 0x9b, 0xb0, 0x88, 0x83, 0x0c, 0x90, 0x91, 0x8a, 0x90, 0xec, -- 0x7f, 0x57, 0xa0, 0xd6, 0x24, 0xbe, 0x9f, 0x8b, 0x75, 0x1f, 0x16, 0x03, 0x0d, 0xa7, 0xd5, 0x97, -- 0x9e, 0x7e, 0x94, 0xdb, 0xe9, 0xc4, 0x9b, 0x63, 0xd4, 0xd0, 0x27, 0xb0, 0x10, 0xaa, 0x65, 0x58, -- 0xd5, 0x9d, 0xea, 0xee, 0xd2, 0xd3, 0xcd, 0x9c, 0xbe, 0x5e, 0xa4, 0x93, 0x28, 0xa1, 0x2f, 0xa0, -- 0xe1, 0x51, 0x21, 0x31, 0x73, 0x89, 0xb0, 0x6a, 0xda, 0xc2, 0xca, 0x59, 0x98, 0x7d, 0x74, 0xae, -- 0x55, 0xd1, 0x2e, 0xd4, 0xdc, 0x30, 0x16, 0xd6, 0x82, 0x36, 0x59, 0xcf, 0x99, 0x34, 0x3b, 0x67, -- 0x8e, 0xd6, 0xb0, 0x5f, 0x40, 0xfd, 0x94, 0x87, 0xdc, 0xe7, 0xbd, 0x21, 0x7a, 0x06, 0xc0, 0xe2, -- 0x00, 0xff, 0xe0, 0x12, 0xdf, 0x17, 0x56, 0x45, 0xdb, 0x6e, 0xe4, 0x6d, 0x89, 0xef, 0x3b, 0x0d, -- 0xa5, 0xa8, 0x9e, 0x84, 0xfd, 0xcf, 0x0a, 0x2c, 0x76, 0xdb, 0x07, 0x94, 0x0b, 0x64, 0xc3, 0x72, -- 0x80, 0x59, 0x7c, 0x89, 0x5d, 0x19, 0x47, 0x24, 0xd2, 0xfb, 0xd4, 0x70, 0xc6, 0xc6, 0x54, 0x16, -- 0x85, 0x11, 0xf7, 0x62, 0x37, 0xdd, 0xe1, 0x54, 0xcc, 0x26, 0x60, 0x75, 0x2c, 0x01, 0xd1, 0x87, -- 0x50, 0x15, 0x57, 0xb1, 0x55, 0xd3, 0xa3, 0xea, 0x51, 0x1d, 0xde, 0x25, 0x0e, 0xa8, 0x3f, 0xb4, -- 0x16, 0xf4, 0xa0, 0x91, 0xec, 0x7f, 0x54, 0xa0, 0x7e, 0x48, 0xc5, 0xd5, 0x09, 0xbb, 0xe4, 0x5a, -- 0x89, 0x47, 0x01, 0x96, 0x26, 0x10, 0x23, 0xa1, 0x1d, 0x58, 0xba, 0xc0, 0xee, 0x15, 0x65, 0xbd, -- 0x23, 0xea, 0x13, 0x13, 0x46, 0x76, 0x08, 0x3d, 0x04, 0x50, 0xf1, 0x62, 0xbf, 0x9b, 0xe6, 0x4f, -- 0xcd, 0xc9, 0x8c, 0x28, 0x04, 0xb5, 0x25, 0xa9, 0x42, 0x4d, 0x2b, 0x64, 0x87, 0xec, 0xff, 0x55, -- 0x60, 0xa5, 0xe9, 0xc7, 0x42, 0x92, 0xa8, 0xc9, 0xd9, 0x25, 0xed, 0xa1, 0x3d, 0x40, 0xad, 0x77, -- 0x21, 0x66, 0x9e, 0x8a, 0x4f, 0xb4, 0x18, 0xbe, 0xf0, 0x49, 0x92, 0x4a, 0x75, 0xa7, 0x60, 0x06, -- 0xfd, 0x1e, 0xb6, 0x8e, 0x22, 0x42, 0x54, 0x3e, 0x38, 0x24, 0xe4, 0x91, 0xa4, 0xac, 0x77, 0x48, -- 0x45, 0x62, 0x36, 0xaf, 0xcd, 0xca, 0x15, 0xd0, 0x73, 0xb0, 0x0e, 0xb8, 0xdb, 0x17, 0x87, 0x54, -- 0x84, 0x3e, 0x1e, 0x1e, 0xf1, 0xa8, 0x75, 0x74, 0x72, 0x1c, 0x13, 0x21, 0x85, 0x5e, 0x4f, 0xdd, -- 0x29, 0x9d, 0x57, 0xb6, 0x5d, 0x12, 0x51, 0xec, 0x37, 0x39, 0x13, 0xdc, 0x27, 0xaf, 0xf8, 0xb5, -- 0xe3, 0x5a, 0x62, 0x5b, 0x36, 0x6f, 0x7f, 0x06, 0x5b, 0x27, 0x4c, 0x92, 0xe8, 0x12, 0xbb, 0xe4, -- 0x80, 0x32, 0x8f, 0xb2, 0x5e, 0x9b, 0xf6, 0x22, 0x2c, 0xd5, 0x39, 0x6e, 0xaa, 0xe2, 0x93, 0x7d, -- 0xee, 0xa5, 0x07, 0x92, 0x48, 0xf6, 0x7f, 0xef, 0xc1, 0xc6, 0x79, 0xb2, 0x79, 0x6d, 0xec, 0xf6, -- 0x29, 0x23, 0x6f, 0x42, 0x65, 0x20, 0xd0, 0x37, 0xb0, 0x3e, 0x3e, 0x91, 0x64, 0x9a, 0xe9, 0x6b, -- 0xf9, 0x6a, 0x4b, 0xa6, 0x9d, 0x42, 0x23, 0xf4, 0x0c, 0x36, 0xda, 0x24, 0x38, 0xc0, 0xbe, 0xcf, -- 0x39, 0xeb, 0x4a, 0x2c, 0x45, 0x87, 0x44, 0x94, 0x27, 0xbb, 0xb9, 0xe2, 0x14, 0x4f, 0xa2, 0xdf, -- 0xc2, 0x5a, 0x27, 0x22, 0x6a, 0xdc, 0xc5, 0x92, 0x78, 0xe7, 0xdc, 0x8f, 0x03, 0x53, 0xbf, 0x0d, -- 0xa7, 0x68, 0x4a, 0x35, 0x60, 0x69, 0x6a, 0x4a, 0xef, 0x57, 0x51, 0x03, 0x4e, 0x8b, 0xce, 0x19, -- 0xa9, 0xa2, 0x2e, 0x34, 0x74, 0x02, 0xa8, 0xdc, 0x35, 0x95, 0xfb, 0x79, 0xce, 0xae, 0x70, 0x9b, -- 0xf6, 0x46, 0x76, 0x2d, 0x26, 0xa3, 0xa1, 0x73, 0x8d, 0x53, 0x92, 0x75, 0x8b, 0xa5, 0x59, 0x77, -- 0x08, 0x2b, 0x6e, 0x36, 0x6d, 0xad, 0x7b, 0x7a, 0x01, 0x0f, 0xf3, 0x6d, 0x20, 0xab, 0xe5, 0x8c, -- 0x1b, 0xa1, 0x9f, 0x2b, 0xb0, 0x45, 0xd3, 0x34, 0x38, 0xe4, 0x01, 0xa6, 0xec, 0xa5, 0x94, 0xd8, -- 0xed, 0x07, 0x84, 0x49, 0xab, 0xae, 0xd7, 0xd6, 0x7a, 0xcf, 0xb5, 0x9d, 0x94, 0xe1, 0x24, 0x6b, -- 0x2d, 0xf7, 0x83, 0x18, 0xa0, 0xd1, 0xe4, 0x28, 0x09, 0xad, 0x86, 0xf6, 0xfe, 0xe5, 0x5d, 0xbd, -- 0x8f, 0x00, 0x12, 0xb7, 0x05, 0xc8, 0xdb, 0x6f, 0x61, 0x75, 0xfc, 0x20, 0x54, 0xe3, 0xba, 0x22, -- 0x43, 0x93, 0xed, 0xea, 0x11, 0xed, 0x67, 0x2f, 0xb7, 0xa2, 0xc4, 0x48, 0xbb, 0x97, 0xb9, 0xf7, -- 0x9e, 0xcf, 0xff, 0xae, 0xb2, 0xfd, 0x0a, 0x1e, 0xde, 0xbc, 0x0b, 0x05, 0x8e, 0xc6, 0x6e, 0xd1, -- 0x46, 0x16, 0xed, 0x47, 0xf8, 0xa8, 0x64, 0x55, 0x05, 0x30, 0x2f, 0xc6, 0xe3, 0xfd, 0x4d, 0x2e, -- 0xde, 0xd2, 0x6a, 0xcf, 0xb8, 0xb4, 0x07, 0x00, 0xe7, 0xed, 0x13, 0x87, 0xfc, 0xa8, 0x1a, 0x0c, -- 0x7a, 0x0c, 0xd5, 0x41, 0x40, 0x4d, 0x0d, 0xe7, 0x2f, 0x27, 0xa5, 0xa9, 0x14, 0xd0, 0x0b, 0xb8, -- 0xc7, 0x93, 0x63, 0x30, 0xde, 0x1f, 0xbf, 0xdf, 0xa1, 0x39, 0xa9, 0x99, 0x7d, 0x0a, 0x1f, 0x5e, -- 0xc7, 0x73, 0x47, 0xef, 0xd6, 0xb8, 0xf7, 0xe5, 0x6b, 0xd4, 0x9f, 0x2b, 0xb0, 0xd4, 0x7a, 0x47, -- 0xdc, 0x14, 0xf1, 0x21, 0x80, 0xa7, 0x4f, 0xe5, 0x35, 0x0e, 0x88, 0xd9, 0xbc, 0xcc, 0x88, 0x42, -- 0x6a, 0xf2, 0x20, 0xc0, 0xcc, 0x4b, 0xaf, 0x3c, 0x23, 0x2a, 0xae, 0xf1, 0x32, 0xea, 0xa5, 0xcd, -- 0x44, 0x3f, 0xa3, 0xc7, 0xb0, 0x2a, 0x69, 0x40, 0x78, 0x2c, 0xbb, 0xc4, 0xe5, 0xcc, 0x13, 0xba, -- 0x87, 0x2c, 0x38, 0x13, 0xa3, 0xf6, 0x2a, 0x2c, 0xb7, 0x82, 0x50, 0x0e, 0x4d, 0x14, 0xf6, 0x97, -- 0x50, 0x77, 0x32, 0x5c, 0x4e, 0xc4, 0xae, 0x4b, 0x84, 0x30, 0x17, 0x4c, 0x2a, 0xaa, 0x99, 0x80, -- 0x08, 0x81, 0x7b, 0x69, 0x62, 0xa4, 0xa2, 0xfd, 0x03, 0xac, 0x26, 0xb9, 0x35, 0x2d, 0x91, 0xdc, -- 0x84, 0xc5, 0x64, 0xf1, 0xc6, 0x83, 0x91, 0x6c, 0x06, 0x6b, 0x89, 0x03, 0xdd, 0x5d, 0xa7, 0xf5, -- 0xb2, 0x03, 0x4b, 0xde, 0x35, 0x5a, 0x7a, 0x89, 0x67, 0x86, 0xec, 0x77, 0x70, 0x5f, 0x5f, 0x68, -- 0xba, 0x9a, 0xa6, 0xf4, 0xf6, 0x09, 0xdc, 0xef, 0x4d, 0x62, 0x19, 0x9f, 0xf9, 0x09, 0xfb, 0xef, -- 0x15, 0xd8, 0xd0, 0xae, 0xcf, 0x04, 0x89, 0x5e, 0x51, 0x21, 0xa7, 0x75, 0xff, 0x0c, 0x36, 0x7a, -- 0x45, 0x78, 0x26, 0x84, 0xe2, 0x49, 0xfb, 0x5f, 0x15, 0xb0, 0x74, 0x18, 0x8a, 0xd3, 0x88, 0xa1, -- 0x90, 0x24, 0x98, 0x7a, 0xdb, 0x9f, 0x83, 0xd5, 0x2b, 0x81, 0x34, 0xc1, 0x94, 0xce, 0xdb, 0x43, -- 0x58, 0x4e, 0xca, 0x66, 0xba, 0x10, 0xb6, 0xa1, 0x4e, 0xde, 0x51, 0xd9, 0xe4, 0x5e, 0xe2, 0x72, -- 0xc1, 0x19, 0xc9, 0x2a, 0xf7, 0x84, 0xf4, 0xde, 0xc4, 0xd2, 0x50, 0x48, 0x23, 0xd9, 0xdf, 0xc1, -- 0x87, 0x7a, 0x27, 0x3a, 0x8a, 0x28, 0xbf, 0x67, 0xd9, 0xe6, 0x0b, 0x71, 0xbe, 0xb0, 0x10, 0xbf, -- 0x36, 0x79, 0x96, 0x60, 0x4f, 0xb5, 0x36, 0x9b, 0xc3, 0x8a, 0xe2, 0x74, 0x3f, 0x91, 0xbb, 0x76, -- 0xab, 0x2f, 0x60, 0x33, 0x66, 0x97, 0xda, 0xf4, 0xb4, 0x28, 0xe8, 0x92, 0x59, 0xfb, 0x2d, 0xdc, -- 0x4f, 0xde, 0x50, 0x0e, 0xe3, 0x20, 0xbc, 0xab, 0xd3, 0x6d, 0xa8, 0x7b, 0x71, 0x10, 0x76, 0xb0, -- 0xec, 0x9b, 0xc3, 0x1f, 0xc9, 0xf6, 0x05, 0x7c, 0xd0, 0x6d, 0x9d, 0xcf, 0xa2, 0xf6, 0x54, 0x33, -- 0x23, 0x03, 0xcd, 0x8a, 0x4c, 0x23, 0x36, 0xa2, 0xfd, 0xb7, 0x0a, 0x6c, 0xbd, 0xd2, 0xef, 0xcc, -- 0x6d, 0x82, 0x45, 0x1c, 0x11, 0x75, 0x21, 0xce, 0xa0, 0xd4, 0xfd, 0x49, 0x4c, 0xe3, 0x38, 0x3f, -- 0x61, 0x7f, 0xaf, 0xf8, 0xee, 0x5f, 0x88, 0x2b, 0x93, 0x38, 0xba, 0xc4, 0x8d, 0x88, 0x9c, 0xdd, -- 0x55, 0xd3, 0x87, 0xb5, 0xf3, 0xf6, 0x49, 0xb3, 0x4f, 0xdc, 0x2b, 0x11, 0x07, 0x33, 0xa8, 0x1c, -- 0xd7, 0x40, 0xa5, 0xe7, 0x95, 0xca, 0x4f, 0xff, 0xb3, 0x0e, 0xd5, 0x66, 0xe0, 0xa1, 0xd7, 0x80, -- 0xba, 0x43, 0xe6, 0x8e, 0x5f, 0xac, 0xe8, 0x17, 0x85, 0xc1, 0x27, 0xcb, 0xdc, 0x2e, 0xf7, 0x6d, -- 0xcf, 0xa1, 0x37, 0xb0, 0xd6, 0xc1, 0xb1, 0x20, 0x33, 0x03, 0xfc, 0x16, 0x36, 0xce, 0x58, 0x38, -- 0x53, 0xc8, 0x2e, 0xac, 0x27, 0x55, 0x37, 0x81, 0x98, 0x67, 0xbd, 0x63, 0xc5, 0x79, 0x33, 0xa8, -- 0x03, 0x9b, 0x67, 0xa6, 0xe6, 0x66, 0x16, 0xe8, 0x29, 0x58, 0x5d, 0x7e, 0x29, 0x1d, 0x72, 0xc1, -- 0xb9, 0x9c, 0x19, 0xaa, 0x03, 0x9b, 0xdd, 0x7e, 0x2c, 0x3d, 0xfe, 0x57, 0x36, 0x33, 0xcc, 0xd7, -- 0x80, 0xbe, 0xa1, 0xbe, 0x3f, 0x33, 0xbc, 0x0e, 0xac, 0x1f, 0x12, 0x9f, 0xc8, 0xd9, 0xed, 0xe5, -- 0x5b, 0xd8, 0x48, 0xb8, 0xe1, 0x24, 0xe4, 0xaf, 0xf2, 0xdf, 0x70, 0x26, 0x38, 0xe4, 0xad, 0x19, -- 0xaf, 0x2a, 0x68, 0x64, 0x74, 0x8a, 0xa3, 0x1e, 0x91, 0x53, 0x44, 0xfa, 0x07, 0x78, 0xd0, 0xc4, -- 0xcc, 0x25, 0x13, 0xbb, 0x79, 0xfd, 0x5e, 0x3d, 0xdd, 0xd1, 0xd3, 0x1e, 0xc3, 0x7e, 0x12, 0x64, -- 0x87, 0x7b, 0x4d, 0x9f, 0x60, 0x16, 0x87, 0x53, 0x60, 0xfe, 0x11, 0x1e, 0x1d, 0x51, 0x86, 0x7d, -- 0x3a, 0x99, 0xf8, 0xb3, 0x08, 0xf8, 0x35, 0xa0, 0xaf, 0xb8, 0x0c, 0xfd, 0xb8, 0xf7, 0x15, 0x17, -- 0xf2, 0x90, 0x0c, 0xa8, 0x4b, 0xc4, 0x14, 0x78, 0x6d, 0x68, 0x1c, 0x13, 0x99, 0xf0, 0x52, 0xf4, -- 0x20, 0xa7, 0x99, 0x65, 0xd8, 0xdb, 0x8f, 0xf2, 0x2f, 0x6b, 0x63, 0x84, 0x59, 0x27, 0xd5, 0xea, -- 0x08, 0x4e, 0xb3, 0xd0, 0xdb, 0x30, 0x7f, 0x5d, 0x82, 0x39, 0xc6, 0x91, 0x75, 0x8b, 0x5a, 0x3e, -- 0x26, 0x72, 0xc4, 0x67, 0x6f, 0x83, 0xb5, 0x73, 0xd3, 0x39, 0x2a, 0xac, 0x41, 0xeb, 0xc7, 0x44, -- 0xf3, 0xc6, 0x5b, 0xe3, 0x7c, 0x5c, 0x0c, 0x98, 0xe3, 0x9c, 0x73, 0xe8, 0x4f, 0x7a, 0x0b, 0x32, -- 0xfc, 0xef, 0x36, 0xe8, 0x8f, 0x8b, 0xa1, 0x8b, 0x18, 0xe4, 0x1c, 0x3a, 0x80, 0x9a, 0xe2, 0x59, -- 0xb7, 0x61, 0xde, 0x78, 0xe6, 0x2d, 0xa8, 0x29, 0x1e, 0x8a, 0x7e, 0x99, 0xc7, 0xb8, 0x7e, 0xab, -- 0xdb, 0x7e, 0x50, 0x32, 0x9b, 0x69, 0xc6, 0x8d, 0x11, 0xef, 0x2b, 0x68, 0x1a, 0x93, 0x7c, 0xb3, -- 0xec, 0x4c, 0xb2, 0xb4, 0x51, 0x57, 0x8f, 0x35, 0x51, 0x35, 0x23, 0x7a, 0x86, 0xec, 0x92, 0xaf, -- 0xcb, 0x19, 0xee, 0x76, 0x5b, 0xcf, 0x53, 0x67, 0x93, 0xf9, 0xd3, 0xe0, 0xee, 0xe9, 0x59, 0xf0, -- 0x8f, 0x83, 0xe9, 0x23, 0x39, 0xd6, 0xd0, 0xec, 0x9c, 0x89, 0x29, 0x2f, 0xbb, 0x1c, 0xa6, 0xf9, -- 0x78, 0x3f, 0x0d, 0x1f, 0x81, 0x63, 0x22, 0x0d, 0x35, 0xbd, 0x6d, 0xf9, 0x3b, 0xf9, 0x0f, 0x8c, -- 0xe3, 0x9c, 0xd6, 0x9e, 0x43, 0x18, 0xd6, 0x8f, 0x89, 0xcc, 0xd1, 0xd0, 0x9b, 0x43, 0xcc, 0x7f, -- 0x47, 0x29, 0xe5, 0xb1, 0xf6, 0x1c, 0xfa, 0x1e, 0x50, 0x9e, 0x64, 0xa2, 0xa2, 0x6f, 0x31, 0x25, -- 0x4c, 0xf4, 0xe6, 0x2d, 0xf9, 0x33, 0x6c, 0x1c, 0x13, 0xf9, 0x32, 0x0c, 0x7d, 0x4a, 0xbc, 0x0c, -- 0xdd, 0xbc, 0x7b, 0x72, 0x14, 0x70, 0x55, 0x7b, 0xee, 0xa0, 0xf6, 0xdd, 0xfc, 0xe0, 0xc9, 0xc5, -- 0xa2, 0xfe, 0x17, 0xeb, 0xb3, 0xff, 0x07, 0x00, 0x00, 0xff, 0xff, 0xba, 0x43, 0xe7, 0x93, 0xf2, -- 0x1a, 0x00, 0x00, -+ // 1910 bytes of a gzipped FileDescriptorProto -+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x59, 0x5f, 0x73, 0xe3, 0xb6, -+ 0x11, 0xb7, 0x2c, 0xd9, 0x96, 0xd6, 0x7f, 0xe2, 0x83, 0xff, 0x84, 0x76, 0x7b, 0x77, 0x2e, 0xa7, -+ 0xf5, 0x38, 0x69, 0x62, 0xf7, 0x9c, 0x4b, 0xa6, 0x73, 0xd3, 0x66, 0xce, 0x96, 0x65, 0xc7, 0xc9, -+ 0xe9, 0x4e, 0xa1, 0x6c, 0xdf, 0x34, 0x6d, 0x9a, 0x81, 0x49, 0x58, 0x62, 0x4d, 0x02, 0x0c, 0x01, -+ 0xaa, 0x56, 0x9e, 0x3a, 0x73, 0x9d, 0x3e, 0x74, 0xa6, 0x1f, 0xa5, 0x9f, 0xa7, 0x6f, 0xfd, 0x16, -+ 0x7d, 0xef, 0x00, 0x04, 0x65, 0x4a, 0x24, 0xed, 0xf3, 0x48, 0x4f, 0x22, 0x80, 0xdd, 0xdf, 0x2e, -+ 0x16, 0xbb, 0x8b, 0x1f, 0x45, 0xf8, 0x28, 0xb8, 0xee, 0xec, 0x75, 0x31, 0x75, 0x3c, 0x12, 0x7e, -+ 0xea, 0xe1, 0x88, 0xda, 0x5d, 0x12, 0x7e, 0x6a, 0x33, 0x7f, 0xcf, 0xf6, 0x9d, 0xbd, 0xde, 0x33, -+ 0xf9, 0xb3, 0x1b, 0x84, 0x4c, 0x30, 0xf4, 0xc1, 0x75, 0x74, 0x49, 0x7a, 0x6e, 0x28, 0x76, 0xe5, -+ 0x5c, 0xef, 0x99, 0x79, 0x05, 0x2b, 0xdf, 0x12, 0x3f, 0xba, 0x20, 0x21, 0x77, 0x19, 0xb5, 0x08, -+ 0x0f, 0x18, 0xe5, 0x04, 0x7d, 0x0e, 0xd5, 0x50, 0x3f, 0x1b, 0xa5, 0xad, 0xd2, 0xce, 0xfc, 0xfe, -+ 0xc6, 0xee, 0x88, 0xea, 0x6e, 0x22, 0x6c, 0x0d, 0x44, 0x91, 0x01, 0x73, 0xbd, 0x18, 0xc9, 0x98, -+ 0xde, 0x2a, 0xed, 0xd4, 0xac, 0x64, 0x68, 0x3e, 0x85, 0xf2, 0x45, 0xf3, 0x54, 0x09, 0xf8, 0xee, -+ 0xd7, 0x9c, 0x51, 0x05, 0xbb, 0x60, 0x25, 0x43, 0xf3, 0x19, 0x94, 0xeb, 0xad, 0x73, 0xb4, 0x04, -+ 0xd3, 0xae, 0xa3, 0xd6, 0x16, 0xad, 0x69, 0xd7, 0x41, 0x9b, 0x50, 0xe5, 0xee, 0xa5, 0xe7, 0xd2, -+ 0x0e, 0x37, 0xa6, 0xb7, 0xca, 0x3b, 0x8b, 0xd6, 0x60, 0x6c, 0xee, 0xc1, 0x5c, 0x3b, 0x7e, 0xce, -+ 0xa8, 0xad, 0xc2, 0x4c, 0x0f, 0x7b, 0x11, 0x51, 0x6e, 0x54, 0xac, 0x78, 0x60, 0x36, 0x60, 0xa6, -+ 0x85, 0x3b, 0x84, 0xcb, 0x65, 0x9b, 0x45, 0x54, 0x28, 0x8d, 0x8a, 0x15, 0x0f, 0x10, 0x82, 0x4a, -+ 0x44, 0x5d, 0xa1, 0x5d, 0x57, 0xcf, 0x72, 0x8e, 0xbb, 0x3f, 0x11, 0xa3, 0xac, 0xa0, 0xd5, 0xb3, -+ 0xf9, 0x1c, 0x66, 0x9b, 0xc4, 0x67, 0x61, 0x1f, 0xad, 0xc3, 0x2c, 0xf6, 0x53, 0x40, 0x7a, 0x94, -+ 0x87, 0x64, 0xfe, 0xa7, 0x04, 0x95, 0x3a, 0xf1, 0xbc, 0x8c, 0xaf, 0x7b, 0x30, 0xeb, 0x2b, 0x38, -+ 0x25, 0x3e, 0xbf, 0xff, 0x61, 0x26, 0xd2, 0xb1, 0x35, 0x4b, 0x8b, 0xa1, 0x4f, 0x60, 0x26, 0x90, -+ 0xdb, 0x30, 0xca, 0x5b, 0xe5, 0x9d, 0xf9, 0xfd, 0xf5, 0x8c, 0xbc, 0xda, 0xa4, 0x15, 0x0b, 0xa1, -+ 0x2f, 0xa0, 0xe6, 0xb8, 0x5c, 0x60, 0x6a, 0x13, 0x6e, 0x54, 0x94, 0x86, 0x91, 0xd1, 0xd0, 0x71, -+ 0xb4, 0x6e, 0x45, 0xd1, 0x0e, 0x54, 0xec, 0x20, 0xe2, 0xc6, 0x8c, 0x52, 0x59, 0xcd, 0xa8, 0xd4, -+ 0x5b, 0xe7, 0x96, 0x92, 0x30, 0x5f, 0x42, 0xf5, 0x8c, 0x05, 0xcc, 0x63, 0x9d, 0x3e, 0x7a, 0x0e, -+ 0x40, 0x23, 0x1f, 0xff, 0x60, 0x13, 0xcf, 0xe3, 0x46, 0x49, 0xe9, 0xae, 0x65, 0x75, 0x89, 0xe7, -+ 0x59, 0x35, 0x29, 0x28, 0x9f, 0xb8, 0xf9, 0xcf, 0x12, 0xcc, 0xb6, 0x9b, 0x87, 0x2e, 0xe3, 0xc8, -+ 0x84, 0x05, 0x1f, 0xd3, 0xe8, 0x0a, 0xdb, 0x22, 0x0a, 0x49, 0xa8, 0xe2, 0x54, 0xb3, 0x86, 0xe6, -+ 0x64, 0x16, 0x05, 0x21, 0x73, 0x22, 0x3b, 0x89, 0x70, 0x32, 0x4c, 0x27, 0x60, 0x79, 0x28, 0x01, -+ 0xd1, 0x32, 0x94, 0xf9, 0x75, 0x64, 0x54, 0xd4, 0xac, 0x7c, 0x94, 0x87, 0x77, 0x85, 0x7d, 0xd7, -+ 0xeb, 0x1b, 0x33, 0x6a, 0x52, 0x8f, 0xcc, 0x7f, 0x94, 0xa0, 0x7a, 0xe4, 0xf2, 0xeb, 0x53, 0x7a, -+ 0xc5, 0x94, 0x10, 0x0b, 0x7d, 0x2c, 0xb4, 0x23, 0x7a, 0x84, 0xb6, 0x60, 0xfe, 0x12, 0xdb, 0xd7, -+ 0x2e, 0xed, 0x1c, 0xbb, 0x1e, 0xd1, 0x6e, 0xa4, 0xa7, 0xd0, 0x13, 0x00, 0xe9, 0x2f, 0xf6, 0xda, -+ 0x49, 0xfe, 0x54, 0xac, 0xd4, 0x8c, 0x44, 0x90, 0x21, 0x49, 0x04, 0x2a, 0x4a, 0x20, 0x3d, 0x65, -+ 0xfe, 0xaf, 0x04, 0x8b, 0x75, 0x2f, 0xe2, 0x82, 0x84, 0x75, 0x46, 0xaf, 0xdc, 0x0e, 0xda, 0x05, -+ 0xd4, 0xb8, 0x09, 0x30, 0x75, 0xa4, 0x7f, 0xbc, 0x41, 0xf1, 0xa5, 0x47, 0xe2, 0x54, 0xaa, 0x5a, -+ 0x39, 0x2b, 0xe8, 0x77, 0xb0, 0x71, 0x1c, 0x12, 0x22, 0xf3, 0xc1, 0x22, 0x01, 0x0b, 0x85, 0x4b, -+ 0x3b, 0x47, 0x2e, 0x8f, 0xd5, 0xa6, 0x95, 0x5a, 0xb1, 0x00, 0x7a, 0x01, 0xc6, 0x21, 0xb3, 0xbb, -+ 0xfc, 0xc8, 0xe5, 0x81, 0x87, 0xfb, 0xc7, 0x2c, 0x6c, 0x1c, 0x9f, 0x9e, 0x44, 0x84, 0x0b, 0xae, -+ 0xf6, 0x53, 0xb5, 0x0a, 0xd7, 0xa5, 0x6e, 0x9b, 0x84, 0x2e, 0xf6, 0xea, 0x8c, 0x72, 0xe6, 0x91, -+ 0x57, 0xec, 0xd6, 0x70, 0x25, 0xd6, 0x2d, 0x5a, 0x37, 0x3f, 0x83, 0x8d, 0x53, 0x2a, 0x48, 0x78, -+ 0x85, 0x6d, 0x72, 0xe8, 0x52, 0xc7, 0xa5, 0x9d, 0xa6, 0xdb, 0x09, 0xb1, 0x90, 0xe7, 0xb8, 0x2e, -+ 0x8b, 0x4f, 0x74, 0x99, 0x93, 0x1c, 0x48, 0x3c, 0x32, 0xff, 0x3b, 0x07, 0x6b, 0x17, 0x71, 0xf0, -+ 0x9a, 0xd8, 0xee, 0xba, 0x94, 0xbc, 0x09, 0xa4, 0x02, 0x47, 0xdf, 0xc0, 0xea, 0xf0, 0x42, 0x9c, -+ 0x69, 0xba, 0xaf, 0x65, 0xab, 0x2d, 0x5e, 0xb6, 0x72, 0x95, 0xd0, 0x73, 0x58, 0x6b, 0x12, 0xff, -+ 0x10, 0x7b, 0x1e, 0x63, 0xb4, 0x2d, 0xb0, 0xe0, 0x2d, 0x12, 0xba, 0x2c, 0x8e, 0xe6, 0xa2, 0x95, -+ 0xbf, 0x88, 0x7e, 0x03, 0x2b, 0xad, 0x90, 0xc8, 0x79, 0x1b, 0x0b, 0xe2, 0x5c, 0x30, 0x2f, 0xf2, -+ 0x75, 0xfd, 0xd6, 0xac, 0xbc, 0x25, 0xd9, 0x80, 0x85, 0xae, 0x29, 0x15, 0xaf, 0xbc, 0x06, 0x9c, -+ 0x14, 0x9d, 0x35, 0x10, 0x45, 0x6d, 0xa8, 0xa9, 0x04, 0x90, 0xb9, 0xab, 0x2b, 0xf7, 0xf3, 0x8c, -+ 0x5e, 0x6e, 0x98, 0x76, 0x07, 0x7a, 0x0d, 0x2a, 0xc2, 0xbe, 0x75, 0x8b, 0x53, 0x90, 0x75, 0xb3, -+ 0x85, 0x59, 0x77, 0x04, 0x8b, 0x76, 0x3a, 0x6d, 0x8d, 0x39, 0xb5, 0x81, 0x27, 0xd9, 0x36, 0x90, -+ 0x96, 0xb2, 0x86, 0x95, 0xd0, 0xbb, 0x12, 0x6c, 0xb8, 0x49, 0x1a, 0x1c, 0x31, 0x1f, 0xbb, 0xf4, -+ 0x40, 0x08, 0x6c, 0x77, 0x7d, 0x42, 0x85, 0x51, 0x55, 0x7b, 0x6b, 0xbc, 0xe7, 0xde, 0x4e, 0x8b, -+ 0x70, 0xe2, 0xbd, 0x16, 0xdb, 0x41, 0x14, 0xd0, 0x60, 0x71, 0x90, 0x84, 0x46, 0x4d, 0x59, 0xff, -+ 0xf2, 0xa1, 0xd6, 0x07, 0x00, 0xb1, 0xd9, 0x1c, 0xe4, 0xcd, 0xb7, 0xb0, 0x34, 0x7c, 0x10, 0xb2, -+ 0x71, 0x5d, 0x93, 0xbe, 0xce, 0x76, 0xf9, 0x88, 0xf6, 0xd2, 0x97, 0x5b, 0x5e, 0x62, 0x24, 0xdd, -+ 0x4b, 0xdf, 0x7b, 0x2f, 0xa6, 0x7f, 0x5b, 0xda, 0x7c, 0x05, 0x4f, 0xee, 0x8e, 0x42, 0x8e, 0xa1, -+ 0xa1, 0x5b, 0xb4, 0x96, 0x46, 0xfb, 0x11, 0x3e, 0x2c, 0xd8, 0x55, 0x0e, 0xcc, 0xcb, 0x61, 0x7f, -+ 0x3f, 0xce, 0xf8, 0x5b, 0x58, 0xed, 0x29, 0x93, 0x66, 0x0f, 0xe0, 0xa2, 0x79, 0x6a, 0x91, 0x1f, -+ 0x65, 0x83, 0x41, 0xdb, 0x50, 0xee, 0xf9, 0xae, 0xae, 0xe1, 0xec, 0xe5, 0x24, 0x25, 0xa5, 0x00, -+ 0x7a, 0x09, 0x73, 0x2c, 0x3e, 0x06, 0x6d, 0x7d, 0xfb, 0xfd, 0x0e, 0xcd, 0x4a, 0xd4, 0xcc, 0x33, -+ 0x58, 0xbe, 0xf5, 0xe7, 0x81, 0xd6, 0x8d, 0x61, 0xeb, 0x0b, 0xb7, 0xa8, 0xef, 0x4a, 0x30, 0xdf, -+ 0xb8, 0x21, 0x76, 0x82, 0xf8, 0x04, 0xc0, 0x51, 0xa7, 0xf2, 0x1a, 0xfb, 0x44, 0x07, 0x2f, 0x35, -+ 0x23, 0x91, 0xea, 0xcc, 0xf7, 0x31, 0x75, 0x92, 0x2b, 0x4f, 0x0f, 0x25, 0xd7, 0x38, 0x08, 0x3b, -+ 0x49, 0x33, 0x51, 0xcf, 0x68, 0x1b, 0x96, 0x84, 0xeb, 0x13, 0x16, 0x89, 0x36, 0xb1, 0x19, 0x75, -+ 0xb8, 0xea, 0x21, 0x33, 0xd6, 0xc8, 0xac, 0xb9, 0x04, 0x0b, 0x0d, 0x3f, 0x10, 0x7d, 0xed, 0x85, -+ 0xf9, 0x25, 0x54, 0xad, 0x14, 0x97, 0xe3, 0x91, 0x6d, 0x13, 0xce, 0xf5, 0x05, 0x93, 0x0c, 0xe5, -+ 0x8a, 0x4f, 0x38, 0xc7, 0x9d, 0x24, 0x31, 0x92, 0xa1, 0xf9, 0x03, 0x2c, 0xc5, 0xb9, 0x35, 0x2e, -+ 0x91, 0x5c, 0x87, 0xd9, 0x78, 0xf3, 0xda, 0x82, 0x1e, 0x99, 0x14, 0x56, 0x62, 0x03, 0xaa, 0xbb, -+ 0x8e, 0x6b, 0x65, 0x0b, 0xe6, 0x9d, 0x5b, 0xb4, 0xe4, 0x12, 0x4f, 0x4d, 0x99, 0x37, 0xf0, 0x48, -+ 0x5d, 0x68, 0xaa, 0x9a, 0xc6, 0xb4, 0xf6, 0x09, 0x3c, 0xea, 0x8c, 0x62, 0x69, 0x9b, 0xd9, 0x05, -+ 0xf3, 0xef, 0x25, 0x58, 0x53, 0xa6, 0xcf, 0x39, 0x09, 0x5f, 0xb9, 0x5c, 0x8c, 0x6b, 0xfe, 0x39, -+ 0xac, 0x75, 0xf2, 0xf0, 0xb4, 0x0b, 0xf9, 0x8b, 0xe6, 0xbf, 0x4a, 0x60, 0x28, 0x37, 0x24, 0xa7, -+ 0xe1, 0x7d, 0x2e, 0x88, 0x3f, 0x76, 0xd8, 0x5f, 0x80, 0xd1, 0x29, 0x80, 0xd4, 0xce, 0x14, 0xae, -+ 0x9b, 0x7d, 0x58, 0x88, 0xcb, 0x66, 0x3c, 0x17, 0x36, 0xa1, 0x4a, 0x6e, 0x5c, 0x51, 0x67, 0x4e, -+ 0x6c, 0x72, 0xc6, 0x1a, 0x8c, 0x65, 0xee, 0x71, 0xe1, 0xbc, 0x89, 0x84, 0xa6, 0x90, 0x7a, 0x64, -+ 0x7e, 0x07, 0xcb, 0x2a, 0x12, 0x2d, 0x49, 0x94, 0xdf, 0xb3, 0x6c, 0xb3, 0x85, 0x38, 0x9d, 0x5b, -+ 0x88, 0x5f, 0xeb, 0x3c, 0x8b, 0xb1, 0xc7, 0xda, 0x9b, 0xc9, 0x60, 0x51, 0x72, 0xba, 0x9f, 0xc8, -+ 0x43, 0xbb, 0xd5, 0x17, 0xb0, 0x1e, 0xd1, 0x2b, 0xa5, 0x7a, 0x96, 0xe7, 0x74, 0xc1, 0xaa, 0xf9, -+ 0x16, 0x1e, 0xc5, 0x6f, 0x28, 0x47, 0x91, 0x1f, 0x3c, 0xd4, 0xe8, 0x26, 0x54, 0x9d, 0xc8, 0x0f, -+ 0x5a, 0x58, 0x74, 0xf5, 0xe1, 0x0f, 0xc6, 0xe6, 0x25, 0x7c, 0xd0, 0x6e, 0x5c, 0x4c, 0xa2, 0xf6, -+ 0x64, 0x33, 0x23, 0x3d, 0xc5, 0x8a, 0x74, 0x23, 0xd6, 0x43, 0xf3, 0x6f, 0x25, 0xd8, 0x78, 0xa5, -+ 0xde, 0x99, 0x9b, 0x04, 0xf3, 0x28, 0x24, 0xf2, 0x42, 0x9c, 0x40, 0xa9, 0x7b, 0xa3, 0x98, 0xda, -+ 0x70, 0x76, 0xc1, 0xfc, 0x5e, 0xf2, 0xdd, 0xbf, 0x10, 0x5b, 0xc4, 0x7e, 0xb4, 0x89, 0x1d, 0x12, -+ 0x31, 0xb9, 0xab, 0xa6, 0x0b, 0x2b, 0x17, 0xcd, 0xd3, 0x7a, 0x97, 0xd8, 0xd7, 0x3c, 0xf2, 0x27, -+ 0x50, 0x39, 0xb6, 0x86, 0x4a, 0xce, 0x2b, 0x19, 0x9b, 0x17, 0xb0, 0x36, 0xb8, 0x2a, 0x5b, 0x21, -+ 0xbb, 0x49, 0xee, 0x15, 0xf4, 0x7b, 0x98, 0xc5, 0xb6, 0x62, 0x4e, 0xd2, 0xd2, 0xd2, 0xfe, 0xaf, -+ 0xb2, 0xaf, 0xb8, 0x43, 0x7a, 0x07, 0x4a, 0xd8, 0xd2, 0x4a, 0x1f, 0xff, 0x1a, 0x56, 0xf3, 0xd6, -+ 0x51, 0x0d, 0x66, 0xda, 0x67, 0x07, 0xd6, 0xd9, 0xf2, 0x14, 0xaa, 0x42, 0xa5, 0x7d, 0xf6, 0xa6, -+ 0xb5, 0x5c, 0xda, 0xff, 0xf7, 0x1a, 0x94, 0xeb, 0xbe, 0x83, 0x5e, 0x03, 0x6a, 0xf7, 0xa9, 0x3d, -+ 0x7c, 0xbb, 0xa3, 0x9f, 0xe5, 0x46, 0x30, 0x76, 0x73, 0xb3, 0x38, 0x00, 0xe6, 0x14, 0x7a, 0x03, -+ 0x2b, 0x2d, 0x1c, 0x71, 0x32, 0x31, 0xc0, 0x6f, 0x61, 0xed, 0x9c, 0x06, 0x13, 0x85, 0x6c, 0xc3, -+ 0x6a, 0x5c, 0xfa, 0x23, 0x88, 0x59, 0xea, 0x3d, 0xd4, 0x21, 0xee, 0x06, 0xb5, 0x60, 0xfd, 0x5c, -+ 0x17, 0xfe, 0xc4, 0x1c, 0x3d, 0x03, 0xa3, 0xcd, 0xae, 0x84, 0x45, 0x2e, 0x19, 0x13, 0x13, 0x43, -+ 0xb5, 0x60, 0xbd, 0xdd, 0x8d, 0x84, 0xc3, 0xfe, 0x4a, 0x27, 0x86, 0xf9, 0x1a, 0xd0, 0x37, 0xae, -+ 0xe7, 0x4d, 0x0c, 0xaf, 0x05, 0xab, 0x47, 0xc4, 0x23, 0x62, 0x72, 0xb1, 0x7c, 0x9b, 0x54, 0xdd, -+ 0x28, 0xe4, 0x2f, 0x8a, 0xab, 0xec, 0x7d, 0x33, 0x5e, 0x56, 0xd0, 0x40, 0xe9, 0x0c, 0x87, 0x1d, -+ 0x22, 0xc6, 0xf0, 0xf4, 0x0f, 0xf0, 0xb8, 0x8e, 0xa9, 0x4d, 0x46, 0xa2, 0x79, 0xfb, 0x72, 0x3f, -+ 0xde, 0xd1, 0xbb, 0x1d, 0x8a, 0xbd, 0xd8, 0xc9, 0x16, 0x73, 0xea, 0x1e, 0xc1, 0x34, 0x0a, 0xc6, -+ 0xc0, 0xfc, 0x23, 0x3c, 0x3d, 0x76, 0x29, 0xf6, 0xdc, 0xd1, 0xc4, 0x9f, 0x84, 0xc3, 0xaf, 0x01, -+ 0x7d, 0xc5, 0x44, 0xe0, 0x45, 0x9d, 0xaf, 0x18, 0x17, 0x47, 0xa4, 0xe7, 0xda, 0x84, 0x8f, 0x81, -+ 0xd7, 0x84, 0xda, 0x09, 0x11, 0x31, 0x39, 0x46, 0x8f, 0x33, 0x92, 0x69, 0x9a, 0xbf, 0xf9, 0x34, -+ 0xfb, 0xc6, 0x38, 0xc4, 0xda, 0x55, 0x52, 0x2d, 0x0d, 0xe0, 0x14, 0x15, 0xbe, 0x0f, 0xf3, 0x97, -+ 0x05, 0x98, 0x43, 0x44, 0x5d, 0xb5, 0xa8, 0x85, 0x13, 0x22, 0x06, 0xa4, 0xfa, 0x3e, 0x58, 0x33, -+ 0xb3, 0x9c, 0xe1, 0xe3, 0x0a, 0xb4, 0x7a, 0x42, 0x14, 0x79, 0xbd, 0xd7, 0xcf, 0xed, 0x7c, 0xc0, -+ 0x0c, 0xf1, 0x9d, 0x42, 0x7f, 0x52, 0x21, 0x48, 0x91, 0xd0, 0xfb, 0xa0, 0x3f, 0xca, 0x87, 0xce, -+ 0xa3, 0xb1, 0x53, 0xe8, 0x10, 0x2a, 0x92, 0xec, 0xdd, 0x87, 0x79, 0xe7, 0x99, 0x37, 0xa0, 0x22, -+ 0xc9, 0x30, 0xfa, 0x79, 0x16, 0xe3, 0xf6, 0xd5, 0x72, 0xf3, 0x71, 0xc1, 0x6a, 0xaa, 0x19, 0xd7, -+ 0x06, 0xe4, 0x33, 0xa7, 0x69, 0x8c, 0x92, 0xde, 0xa2, 0x33, 0x49, 0x73, 0x57, 0x55, 0x3d, 0xc6, -+ 0x48, 0xd5, 0x0c, 0x38, 0x22, 0x32, 0x0b, 0xfe, 0xe2, 0x4e, 0x11, 0xc8, 0xfb, 0x7a, 0x9e, 0x3c, -+ 0x9b, 0xd4, 0x97, 0x8b, 0x87, 0xa7, 0x67, 0xce, 0x67, 0x0f, 0xdd, 0x47, 0x32, 0xac, 0xa1, 0xde, -+ 0x3a, 0xe7, 0x63, 0x5e, 0x76, 0x19, 0x4c, 0xfd, 0x05, 0x61, 0x1c, 0x3e, 0x02, 0x27, 0x44, 0x68, -+ 0x7e, 0x7c, 0xdf, 0xf6, 0xb7, 0xb2, 0xff, 0x72, 0x0e, 0x13, 0x6b, 0x73, 0x0a, 0x61, 0x58, 0x3d, -+ 0x21, 0x22, 0xc3, 0x85, 0xef, 0x76, 0x31, 0xfb, 0x67, 0x4e, 0x21, 0x99, 0x36, 0xa7, 0xd0, 0xf7, -+ 0x80, 0xb2, 0x4c, 0x17, 0xe5, 0xfd, 0x21, 0x54, 0x40, 0x87, 0xef, 0x0e, 0xc9, 0x9f, 0x61, 0xed, -+ 0x84, 0x88, 0x83, 0x20, 0xf0, 0x5c, 0xe2, 0xa4, 0x38, 0xef, 0xc3, 0x93, 0x23, 0x87, 0x30, 0xab, -+ 0x36, 0xb3, 0x34, 0xcc, 0x43, 0xd1, 0xf6, 0x3d, 0x44, 0xf6, 0x7e, 0xb7, 0x0f, 0x2b, 0xdf, 0x4d, -+ 0xf7, 0x9e, 0x5d, 0xce, 0xaa, 0xef, 0x73, 0x9f, 0xfd, 0x3f, 0x00, 0x00, 0xff, 0xff, 0xb2, 0x87, -+ 0xe8, 0xd2, 0xcc, 0x1b, 0x00, 0x00, - } -diff --git a/pkg/handler-launcher-com/cmd/v1/cmd.proto b/pkg/handler-launcher-com/cmd/v1/cmd.proto -index e2d6be51f1..ec6fc21896 100644 ---- a/pkg/handler-launcher-com/cmd/v1/cmd.proto -+++ b/pkg/handler-launcher-com/cmd/v1/cmd.proto -@@ -35,6 +35,7 @@ service Cmd { - rpc GetLaunchMeasurement(VMIRequest) returns (LaunchMeasurementResponse) {} - rpc InjectLaunchSecret(InjectLaunchSecretRequest) returns (Response) {} - rpc GetAppliedVMIChecksum(EmptyRequest) returns (VMIChecksumResponse) {} -+ rpc MigrationProxy(MigrationProxyRequest) returns (Response); - } - - message QemuVersionResponse { -@@ -211,3 +212,12 @@ message VMIChecksumResponse { - Response response = 1; - string checksum = 2; - } -+ -+enum MigrationProxyAction { -+ START = 0; -+ STOP = 1; -+} -+ -+message MigrationProxyRequest { -+ MigrationProxyAction action = 1; -+} -\ No newline at end of file -diff --git a/pkg/virt-handler/cmd-client/client.go b/pkg/virt-handler/cmd-client/client.go -index 68213c6456..7f973c9701 100644 ---- a/pkg/virt-handler/cmd-client/client.go -+++ b/pkg/virt-handler/cmd-client/client.go -@@ -114,6 +114,7 @@ type LauncherClient interface { - InjectLaunchSecret(*v1.VirtualMachineInstance, *v1.SEVSecretOptions) error - SyncVirtualMachineMemory(vmi *v1.VirtualMachineInstance, options *cmdv1.VirtualMachineOptions) error - GetAppliedVMIChecksum() (string, error) -+ MigrationProxy(action MigrationProxyAction) error - } - - type VirtLauncherClient struct { -@@ -882,3 +883,22 @@ func (c *VirtLauncherClient) GetAppliedVMIChecksum() (string, error) { - log.Log.Reason(err).Error("error getting the checksum") - return "", errors.New("error getting the checksum") - } -+ -+type MigrationProxyAction int32 -+ -+const ( -+ MigrationProxyActionStart = iota -+ MigrationProxyActionStop -+) -+ -+func (c *VirtLauncherClient) MigrationProxy(action MigrationProxyAction) error { -+ request := &cmdv1.MigrationProxyRequest{ -+ Action: cmdv1.MigrationProxyAction(action), -+ } -+ ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) -+ defer cancel() -+ -+ response, err := c.v1client.MigrationProxy(ctx, request) -+ -+ return handleError(err, "MigrationProxy", response) -+} -diff --git a/pkg/virt-handler/migration-proxy/migration-proxy.go b/pkg/virt-handler/migration-proxy/migration-proxy.go -index f3226b06fc..d6538add0a 100644 ---- a/pkg/virt-handler/migration-proxy/migration-proxy.go -+++ b/pkg/virt-handler/migration-proxy/migration-proxy.go -@@ -374,7 +374,22 @@ func NewTargetProxy(tcpBindAddress string, tcpBindPort int, serverTLSConfig *tls - clientTLSConfig: clientTLSConfig, - logger: log.Log.With("uid", vmiUID).With("outbound", filepath.Base(virtqemudSocketPath)), - } -+} - -+func NewVirtLauncherProxy() *migrationProxy { -+ const ( -+ migrationProxySock = "/var/run/kubevirt/migrationproxy/wrap-virtqemud-sock" -+ virtQemudSock = "/var/run/libvirt/virtqemud-sock" -+ ) -+ return &migrationProxy{ -+ unixSocketPath: migrationProxySock, -+ targetAddress: virtQemudSock, -+ targetProtocol: "unix", -+ stopChan: make(chan struct{}), -+ fdChan: make(chan net.Conn, 1), -+ listenErrChan: make(chan error, 1), -+ logger: log.Log.With("migrationProxySock", migrationProxySock, "virtQemudSock", virtQemudSock, "proxy", "virt-launcher"), -+ } - } - - func (m *migrationProxy) createTcpListener() error { -diff --git a/pkg/virt-handler/vm.go b/pkg/virt-handler/vm.go -index 0e8825cfd2..d29380f8f4 100644 ---- a/pkg/virt-handler/vm.go -+++ b/pkg/virt-handler/vm.go -@@ -2643,7 +2643,7 @@ func (d *VirtualMachineController) isMigrationSource(vmi *v1.VirtualMachineInsta - - } - --func (d *VirtualMachineController) handleTargetMigrationProxy(vmi *v1.VirtualMachineInstance) error { -+func (d *VirtualMachineController) handleTargetMigrationProxy(vmi *v1.VirtualMachineInstance, client cmdclient.LauncherClient) error { - // handle starting/stopping target migration proxy - migrationTargetSockets := []string{} - res, err := d.podIsolationDetector.Detect(vmi) -@@ -2651,8 +2651,10 @@ func (d *VirtualMachineController) handleTargetMigrationProxy(vmi *v1.VirtualMac - return err - } - -- // Get the libvirt connection socket file on the destination pod. -- socketFile := fmt.Sprintf(filepath.Join(d.virtLauncherFSRunDirPattern, "libvirt/virtqemud-sock"), res.Pid()) -+ // Get the virt-launcher migration proxy connection socket file on the destination pod. -+ socketFile := fmt.Sprintf(filepath.Join(d.virtLauncherFSRunDirPattern, "kubevirt/migrationproxy/wrap-virtqemud-sock"), res.Pid()) -+ //// Get the libvirt connection socket file on the destination pod. -+ //socketFile := fmt.Sprintf(filepath.Join(d.virtLauncherFSRunDirPattern, "libvirt/virtqemud-sock"), res.Pid()) - // the migration-proxy is no longer shared via host mount, so we - // pass in the virt-launcher's baseDir to reach the unix sockets. - baseDir := fmt.Sprintf(filepath.Join(d.virtLauncherFSRunDirPattern, "kubevirt"), res.Pid()) -@@ -2666,6 +2668,10 @@ func (d *VirtualMachineController) handleTargetMigrationProxy(vmi *v1.VirtualMac - destSocketFile := migrationproxy.SourceUnixFile(baseDir, key) - migrationTargetSockets = append(migrationTargetSockets, destSocketFile) - } -+ err = d.StartMigrationProxyInVirtLauncher(client) -+ if err != nil { -+ return err -+ } - err = d.migrationProxy.StartTargetListener(string(vmi.UID), migrationTargetSockets) - if err != nil { - return err -@@ -2673,11 +2679,21 @@ func (d *VirtualMachineController) handleTargetMigrationProxy(vmi *v1.VirtualMac - return nil - } - --func (d *VirtualMachineController) handlePostMigrationProxyCleanup(vmi *v1.VirtualMachineInstance) { -+func (d *VirtualMachineController) handlePostMigrationProxyCleanup(vmi *v1.VirtualMachineInstance) error { - if vmi.Status.MigrationState == nil || vmi.Status.MigrationState.Completed || vmi.Status.MigrationState.Failed { -+ if !d.isMigrationSource(vmi) { -+ client, err := d.getLauncherClient(vmi) -+ if err != nil { -+ return fmt.Errorf("failed to get virt-launcher client") -+ } -+ if err = d.StopMigrationProxyInVirtLauncher(client); err != nil { -+ return fmt.Errorf("failed to stop migration proxy in virt launcher") -+ } -+ } - d.migrationProxy.StopTargetListener(string(vmi.UID)) - d.migrationProxy.StopSourceListener(string(vmi.UID)) - } -+ return nil - } - - func (d *VirtualMachineController) handleSourceMigrationProxy(vmi *v1.VirtualMachineInstance) error { -@@ -2968,7 +2984,7 @@ func (d *VirtualMachineController) vmUpdateHelperMigrationTarget(origVMI *v1.Vir - } - d.recorder.Event(vmi, k8sv1.EventTypeNormal, v1.PreparingTarget.String(), "VirtualMachineInstance Migration Target Prepared.") - -- err = d.handleTargetMigrationProxy(vmi) -+ err = d.handleTargetMigrationProxy(vmi, client) - if err != nil { - return fmt.Errorf("failed to handle post sync migration proxy: %v", err) - } -@@ -3405,7 +3421,9 @@ func (d *VirtualMachineController) processVmUpdate(vmi *v1.VirtualMachineInstanc - return goerror.New(fmt.Sprintf("Can not update a VirtualMachineInstance with unresponsive command server.")) - } - -- d.handlePostMigrationProxyCleanup(vmi) -+ if err = d.handlePostMigrationProxyCleanup(vmi); err != nil { -+ return err -+ } - - if d.isPreMigrationTarget(vmi) { - return d.vmUpdateHelperMigrationTarget(vmi) -@@ -3913,3 +3931,11 @@ func (d *VirtualMachineController) HotplugHostDevices(client cmdclient.LauncherC - d.checksumCtrl.Set(control) - return nil - } -+ -+func (d *VirtualMachineController) StartMigrationProxyInVirtLauncher(client cmdclient.LauncherClient) error { -+ return client.MigrationProxy(cmdclient.MigrationProxyActionStart) -+} -+ -+func (d *VirtualMachineController) StopMigrationProxyInVirtLauncher(client cmdclient.LauncherClient) error { -+ return client.MigrationProxy(cmdclient.MigrationProxyActionStop) -+} -diff --git a/pkg/virt-launcher/virtwrap/cmd-server/server.go b/pkg/virt-launcher/virtwrap/cmd-server/server.go -index 2be5af2eb3..0612e653a6 100644 ---- a/pkg/virt-launcher/virtwrap/cmd-server/server.go -+++ b/pkg/virt-launcher/virtwrap/cmd-server/server.go -@@ -27,7 +27,6 @@ import ( - "time" - - "google.golang.org/grpc" -- - "k8s.io/apimachinery/pkg/util/json" - - v1 "kubevirt.io/api/core/v1" -@@ -753,6 +752,36 @@ func (l *Launcher) GetAppliedVMIChecksum(_ context.Context, _ *cmdv1.EmptyReques - return response, nil - } - -+func (l *Launcher) MigrationProxy(_ context.Context, req *cmdv1.MigrationProxyRequest) (*cmdv1.Response, error) { -+ response := &cmdv1.Response{ -+ Success: true, -+ } -+ if req == nil { -+ response.Success = false -+ response.Message = getErrorMessage(fmt.Errorf("nil request")) -+ return response, nil -+ } -+ -+ switch req.Action { -+ case cmdv1.MigrationProxyAction_START: -+ response.Message = "Migration proxy was started" -+ case cmdv1.MigrationProxyAction_STOP: -+ response.Message = "Migration proxy was stopped" -+ default: -+ response.Success = false -+ response.Message = getErrorMessage(fmt.Errorf("unsupported action %d", req.Action)) -+ return response, nil -+ } -+ -+ if err := l.domainManager.MigrationProxy(req.GetAction()); err != nil { -+ response.Success = false -+ response.Message = getErrorMessage(err) -+ return response, nil -+ } -+ -+ return response, nil -+} -+ - func ReceivedEarlyExitSignal() bool { - _, earlyExit := os.LookupEnv(receivedEarlyExitSignalEnvVar) - return earlyExit -diff --git a/pkg/virt-launcher/virtwrap/manager.go b/pkg/virt-launcher/virtwrap/manager.go -index c6e675d1b8..200ec52e90 100644 ---- a/pkg/virt-launcher/virtwrap/manager.go -+++ b/pkg/virt-launcher/virtwrap/manager.go -@@ -44,6 +44,7 @@ import ( - - "kubevirt.io/kubevirt/pkg/util/checksum" - "kubevirt.io/kubevirt/pkg/util/syncobject" -+ migrationproxy "kubevirt.io/kubevirt/pkg/virt-handler/migration-proxy" - virtcache "kubevirt.io/kubevirt/tools/cache" - - "k8s.io/utils/pointer" -@@ -148,6 +149,7 @@ type DomainManager interface { - InjectLaunchSecret(*v1.VirtualMachineInstance, *v1.SEVSecretOptions) error - UpdateGuestMemory(vmi *v1.VirtualMachineInstance) error - GetAppliedVMIChecksum() string -+ MigrationProxy(action cmdv1.MigrationProxyAction) error - } - - type LibvirtDomainManager struct { -@@ -180,9 +182,49 @@ type LibvirtDomainManager struct { - metadataCache *metadata.Cache - domainStatsCache *virtcache.TimeDefinedCache[*stats.DomainStats] - -- checksum syncobject.SyncObject[string] -- -+ checksum syncobject.SyncObject[string] - rebootShutdownPolicyWasSet bool -+ migrationProxy *migrationProxyManager -+} -+ -+type migrationProxyManager struct { -+ started bool -+ mu sync.Mutex -+ migrationProxy migrationproxy.MigrationProxyListener -+} -+ -+func (m *migrationProxyManager) Start() error { -+ m.mu.Lock() -+ defer m.mu.Unlock() -+ if m.started { -+ return nil -+ } -+ m.migrationProxy = migrationproxy.NewVirtLauncherProxy() -+ err := m.migrationProxy.Start() -+ if err != nil { -+ m.migrationProxy.Stop() -+ m.reset() -+ return fmt.Errorf("failed to start migration proxy in virt-launcher") -+ } -+ m.started = true -+ return nil -+} -+ -+func (m *migrationProxyManager) Stop() { -+ m.mu.Lock() -+ defer m.mu.Unlock() -+ if !m.started { -+ return -+ } -+ if m.migrationProxy != nil { -+ m.migrationProxy.Stop() -+ } -+ m.reset() -+} -+ -+func (m *migrationProxyManager) reset() { -+ m.migrationProxy = nil -+ m.started = false - } - - type pausedVMIs struct { -@@ -230,7 +272,8 @@ func newLibvirtDomainManager(connection cli.Connection, virtShareDir, ephemeralD - migrateInfoStats: &stats.DomainJobInfo{}, - metadataCache: metadataCache, - -- checksum: syncobject.NewSyncObject[string](), -+ checksum: syncobject.NewSyncObject[string](), -+ migrationProxy: &migrationProxyManager{}, - } - - manager.hotplugHostDevicesInProgress = make(chan struct{}, maxConcurrentHotplugHostDevices) -@@ -2412,3 +2455,15 @@ func (l *LibvirtDomainManager) setRebootShutdownPolicy(dom cli.VirDomain) error - l.rebootShutdownPolicyWasSet = true - return nil - } -+ -+func (l *LibvirtDomainManager) MigrationProxy(action cmdv1.MigrationProxyAction) error { -+ switch action { -+ case cmdv1.MigrationProxyAction_START: -+ return l.migrationProxy.Start() -+ case cmdv1.MigrationProxyAction_STOP: -+ l.migrationProxy.Stop() -+ return nil -+ default: -+ return fmt.Errorf("unsupported action %d", action) -+ } -+} -diff --git a/pkg/virt-launcher/virtwrap/util/libvirt_helper.go b/pkg/virt-launcher/virtwrap/util/libvirt_helper.go -index 99ce4370f6..34e8229cad 100644 ---- a/pkg/virt-launcher/virtwrap/util/libvirt_helper.go -+++ b/pkg/virt-launcher/virtwrap/util/libvirt_helper.go -@@ -220,6 +220,7 @@ func (l LibvirtWrapper) StartVirtquemud(stopChan chan struct{}) { - exitChan := make(chan struct{}) - args := []string{"-f", "/var/run/libvirt/virtqemud.conf", "--no-admin-srv", "--no-ro-srv"} - cmd := exec.Command("/usr/sbin/virtqemud", args...) -+ cmd.Env = append(cmd.Env, fmt.Sprintf("LIBVIRT_UNIX_SOCKET_AUTH_PID=%d", os.Getpid())) - if l.user != 0 { - cmd.SysProcAttr = &syscall.SysProcAttr{ - AmbientCaps: []uintptr{unix.CAP_NET_BIND_SERVICE}, diff --git a/images/virt-artifact/patches/043-add-qemu-and-libvirt-versions.patch b/images/virt-artifact/patches/043-add-qemu-and-libvirt-versions.patch deleted file mode 100644 index ddc2f8344b..0000000000 --- a/images/virt-artifact/patches/043-add-qemu-and-libvirt-versions.patch +++ /dev/null @@ -1,48 +0,0 @@ -diff --git a/pkg/virt-controller/watch/vm.go b/pkg/virt-controller/watch/vm.go -index 0b4ab053d8..876366aeff 100644 ---- a/pkg/virt-controller/watch/vm.go -+++ b/pkg/virt-controller/watch/vm.go -@@ -27,6 +27,7 @@ import ( - "maps" - "math" - "math/rand" -+ "os" - "strconv" - "strings" - "time" -@@ -124,6 +125,16 @@ const ( - - const defaultMaxCrashLoopBackoffDelaySeconds = 300 - -+const ( -+ libvirtAnn = "versions.virtualization.deckhouse.io/libvirt-version" -+ qemuAnn = "versions.virtualization.deckhouse.io/qemu-version" -+) -+ -+var ( -+ libvirtVersion = os.Getenv("LIBVIRT_VERSION") -+ qemuVersion = os.Getenv("QEMU_VERSION") -+) -+ - func NewVMController(vmiInformer cache.SharedIndexInformer, - vmInformer cache.SharedIndexInformer, - dataVolumeInformer cache.SharedIndexInformer, -@@ -1849,6 +1860,18 @@ func (c *VMController) setupVMIFromVM(vm *virtv1.VirtualMachine) *virtv1.Virtual - *metav1.NewControllerRef(vm, virtv1.VirtualMachineGroupVersionKind), - } - -+ if vmi.Annotations == nil { -+ vmi.Annotations = make(map[string]string) -+ } -+ -+ if libvirtVersion != "" { -+ vmi.Annotations[libvirtAnn] = libvirtVersion -+ } -+ -+ if qemuVersion != "" { -+ vmi.Annotations[qemuAnn] = qemuVersion -+ } -+ - return vmi - } - diff --git a/images/virt-artifact/patches/044-disable-workload-updater.patch b/images/virt-artifact/patches/044-disable-workload-updater.patch deleted file mode 100644 index 85f11cc70b..0000000000 --- a/images/virt-artifact/patches/044-disable-workload-updater.patch +++ /dev/null @@ -1,37 +0,0 @@ -diff --git a/pkg/virt-controller/watch/application.go b/pkg/virt-controller/watch/application.go -index 17711edba5..b2d00679c9 100644 ---- a/pkg/virt-controller/watch/application.go -+++ b/pkg/virt-controller/watch/application.go -@@ -91,10 +91,10 @@ import ( - ) - - const ( -- defaultPort = 8182 -+ defaultPort = 8182 - defaultMetricsPort = 8080 - -- defaultHost = "0.0.0.0" -+ defaultHost = "0.0.0.0" - defaultMetricsHost = defaultHost - - launcherImage = "virt-launcher" -@@ -446,7 +446,8 @@ func Execute() { - app.initSnapshotController() - app.initRestoreController() - app.initExportController() -- app.initWorkloadUpdaterController() -+ // Disable workload-updater -+ // app.initWorkloadUpdaterController() - app.initCloneController() - go app.Run() - -@@ -589,7 +590,8 @@ func (vca *VirtControllerApp) onStartedLeading() func(ctx context.Context) { - log.Log.Warningf("error running the export controller: %v", err) - } - }() -- go vca.workloadUpdateController.Run(stop) -+ // Disable workloadUpdateController -+ // go vca.workloadUpdateController.Run(stop) - go vca.nodeTopologyUpdater.Run(vca.nodeTopologyUpdatePeriod, stop) - go func() { - if err := vca.vmCloneController.Run(vca.cloneControllerThreads, stop); err != nil { diff --git a/images/virt-artifact/patches/045-virt-launcher-image-holder-command-sleep.patch b/images/virt-artifact/patches/045-virt-launcher-image-holder-command-sleep.patch deleted file mode 100644 index 8f9f5c3609..0000000000 --- a/images/virt-artifact/patches/045-virt-launcher-image-holder-command-sleep.patch +++ /dev/null @@ -1,15 +0,0 @@ -diff --git a/pkg/virt-operator/resource/generate/components/daemonsets.go b/pkg/virt-operator/resource/generate/components/daemonsets.go -index 93c55c1619..ebc1e790bf 100644 ---- a/pkg/virt-operator/resource/generate/components/daemonsets.go -+++ b/pkg/virt-operator/resource/generate/components/daemonsets.go -@@ -145,8 +145,8 @@ func NewHandlerDaemonSet(namespace, repository, imagePrefix, version, launcherVe - Name: "virt-launcher-image-holder", - Image: launcherImage, - ImagePullPolicy: corev1.PullIfNotPresent, -- Command: []string{"/bin/sh", "-c"}, -- Args: []string{"sleep infinity"}, -+ Command: []string{"sleep"}, -+ Args: []string{"infinity"}, - Resources: corev1.ResourceRequirements{ - Limits: map[corev1.ResourceName]resource.Quantity{ - corev1.ResourceCPU: resource.MustParse("100m"), diff --git a/images/virt-artifact/patches/046-hotplug-attachment-trigger-pod-remove-bash.patch b/images/virt-artifact/patches/046-hotplug-attachment-trigger-pod-remove-bash.patch deleted file mode 100644 index 0837dcd0ba..0000000000 --- a/images/virt-artifact/patches/046-hotplug-attachment-trigger-pod-remove-bash.patch +++ /dev/null @@ -1,60 +0,0 @@ -diff --git a/pkg/virt-controller/services/template.go b/pkg/virt-controller/services/template.go -index 1221448946..7e2519d129 100644 ---- a/pkg/virt-controller/services/template.go -+++ b/pkg/virt-controller/services/template.go -@@ -382,9 +382,7 @@ func (t *templateService) renderLaunchManifest(vmi *v1.VirtualMachineInstance, i - if tempPod { - logger := log.DefaultLogger() - logger.Infof("RUNNING doppleganger pod for %s", vmi.Name) -- command = []string{"/bin/bash", -- "-c", -- "echo", "bound PVCs"} -+ command = []string{"temp_pod"} - } else { - command = []string{"/usr/bin/virt-launcher-monitor", - "--qemu-timeout", generateQemuTimeoutWithJitter(t.launcherQemuTimeout), -@@ -921,7 +919,7 @@ func (t *templateService) RenderHotplugAttachmentPodTemplate(volumes []*v1.Volum - zero := int64(0) - runUser := int64(util.NonRootUID) - sharedMount := k8sv1.MountPropagationHostToContainer -- command := []string{"/bin/sh", "-c", "/usr/bin/container-disk --copy-path /path/hp"} -+ command := []string{"/usr/bin/container-disk", "--copy-path", "/path/hp"} - - tmpTolerations := make([]k8sv1.Toleration, len(ownerPod.Spec.Tolerations)) - copy(tmpTolerations, ownerPod.Spec.Tolerations) -@@ -1076,11 +1074,9 @@ func (t *templateService) RenderHotplugAttachmentTriggerPodTemplate(volume *v1.V - sharedMount := k8sv1.MountPropagationHostToContainer - var command []string - if tempPod { -- command = []string{"/bin/bash", -- "-c", -- "exit", "0"} -+ command = []string{"temp_pod"} - } else { -- command = []string{"/bin/sh", "-c", "/usr/bin/container-disk --copy-path /path/hp"} -+ command = []string{"/usr/bin/container-disk", "--copy-path", "/path/hp"} - } - - annotationsList := make(map[string]string) -diff --git a/pkg/virt-controller/watch/vmi_test.go b/pkg/virt-controller/watch/vmi_test.go -index b4b76bd73e..9fb2c56118 100644 ---- a/pkg/virt-controller/watch/vmi_test.go -+++ b/pkg/virt-controller/watch/vmi_test.go -@@ -400,7 +400,7 @@ var _ = Describe("VirtualMachineInstance watcher", func() { - - return "" - }, -- Equal("/bin/bash -c echo bound PVCs"), -+ Equal("temp_pod"), - ) - - controller.Execute() -@@ -676,7 +676,7 @@ var _ = Describe("VirtualMachineInstance watcher", func() { - - return "" - }, -- Equal("/bin/bash -c echo bound PVCs")) -+ Equal("temp_pod")) - expectMatchingPodCreation(vmi, IsPodWithoutVmPayload) - expectVMIWithMatcherConditions(vmi.Namespace, vmi.Name, ContainElement(MatchFields(IgnoreExtras, - Fields{"Type": Equal(virtv1.VirtualMachineInstanceProvisioning)})), diff --git a/images/virt-artifact/patches/047-node-labeller-replace-sysctl-command-with-readfile.patch b/images/virt-artifact/patches/047-node-labeller-replace-sysctl-command-with-readfile.patch deleted file mode 100644 index a3b8fd978f..0000000000 --- a/images/virt-artifact/patches/047-node-labeller-replace-sysctl-command-with-readfile.patch +++ /dev/null @@ -1,28 +0,0 @@ -diff --git a/pkg/virt-handler/node-labeller/node_labeller.go b/pkg/virt-handler/node-labeller/node_labeller.go -index e5ddaf3784..8de36d72c9 100644 ---- a/pkg/virt-handler/node-labeller/node_labeller.go -+++ b/pkg/virt-handler/node-labeller/node_labeller.go -@@ -23,7 +23,7 @@ import ( - "context" - "encoding/json" - "fmt" -- "os/exec" -+ "os" - "runtime" - "strings" - "time" -@@ -327,11 +327,12 @@ const kernelSchedRealtimeRuntimeInMicrosecods = "kernel.sched_rt_runtime_us" - // workloads at peak performance. - - func isNodeRealtimeCapable() (bool, error) { -- ret, err := exec.Command("sysctl", kernelSchedRealtimeRuntimeInMicrosecods).CombinedOutput() -+ ret, err := os.ReadFile("/proc/sys/kernel/sched_rt_runtime_us") - if err != nil { - return false, err - } -- st := strings.Trim(string(ret), "\n") -+ sched_rt_runtime_us := strings.Trim(string(ret), "\n") -+ st := fmt.Sprintf("%s = %s", kernelSchedRealtimeRuntimeInMicrosecods, sched_rt_runtime_us) - return fmt.Sprintf("%s = -1", kernelSchedRealtimeRuntimeInMicrosecods) == st, nil - } - diff --git a/images/virt-artifact/patches/048-disable-evacuation-controller.patch b/images/virt-artifact/patches/048-disable-evacuation-controller.patch deleted file mode 100644 index 8d70a83a0b..0000000000 --- a/images/virt-artifact/patches/048-disable-evacuation-controller.patch +++ /dev/null @@ -1,25 +0,0 @@ -diff --git a/pkg/virt-controller/watch/application.go b/pkg/virt-controller/watch/application.go -index b2d00679c9..c469f9e658 100644 ---- a/pkg/virt-controller/watch/application.go -+++ b/pkg/virt-controller/watch/application.go -@@ -442,7 +442,8 @@ func Execute() { - app.initPool() - app.initVirtualMachines() - app.initDisruptionBudgetController() -- app.initEvacuationController() -+ // Disable evacuation controller -+ // app.initEvacuationController() - app.initSnapshotController() - app.initRestoreController() - app.initExportController() -@@ -566,8 +567,8 @@ func (vca *VirtControllerApp) onStartedLeading() func(ctx context.Context) { - if err := metrics.CreateVMIMigrationHandler(vca.migrationInformer); err != nil { - golog.Fatalf("failed to add vmi phase transition time handler: %v", err) - } -- -- go vca.evacuationController.Run(vca.evacuationControllerThreads, stop) -+ // Disable evacuation controller -+ // go vca.evacuationController.Run(vca.evacuationControllerThreads, stop) - go vca.disruptionBudgetController.Run(vca.disruptionBudgetControllerThreads, stop) - go vca.nodeController.Run(vca.nodeControllerThreads, stop) - go vca.vmiController.Run(vca.vmiControllerThreads, stop) diff --git a/images/virt-artifact/patches/049-implement-evacuate-cancel-subresource.patch b/images/virt-artifact/patches/049-implement-evacuate-cancel-subresource.patch deleted file mode 100644 index 357ca271ef..0000000000 --- a/images/virt-artifact/patches/049-implement-evacuate-cancel-subresource.patch +++ /dev/null @@ -1,597 +0,0 @@ -diff --git a/api/openapi-spec/swagger.json b/api/openapi-spec/swagger.json -index d6bb534249..df85d78315 100644 ---- a/api/openapi-spec/swagger.json -+++ b/api/openapi-spec/swagger.json -@@ -8255,6 +8255,67 @@ - } - ] - }, -+ "/apis/subresources.kubevirt.io/v1/namespaces/{namespace}/virtualmachineinstances/{name}/evacuatecancel": { -+ "put": { -+ "description": "Cancel evacuation Virtual Machine Instance", -+ "consumes": [ -+ "*/*" -+ ], -+ "operationId": "v1vmi-evacuatecancel", -+ "parameters": [ -+ { -+ "name": "body", -+ "in": "body", -+ "required": true, -+ "schema": { -+ "$ref": "#/definitions/v1.EvacuateCancelOptions" -+ } -+ } -+ ], -+ "responses": { -+ "200": { -+ "description": "OK", -+ "schema": { -+ "type": "string" -+ } -+ }, -+ "400": { -+ "description": "Bad Request", -+ "schema": { -+ "type": "string" -+ } -+ }, -+ "401": { -+ "description": "Unauthorized" -+ }, -+ "404": { -+ "description": "Not Found", -+ "schema": { -+ "type": "string" -+ } -+ }, -+ "500": { -+ "description": "Internal Server Error", -+ "schema": { -+ "type": "string" -+ } -+ } -+ } -+ }, -+ "parameters": [ -+ { -+ "uniqueItems": true, -+ "type": "string", -+ "description": "Name of the resource", -+ "name": "name", -+ "in": "path", -+ "required": true -+ }, -+ { -+ "$ref": "#/parameters/namespace-nfszEHZ0" -+ } -+ ] -+ }, - "/apis/subresources.kubevirt.io/v1/namespaces/{namespace}/virtualmachineinstances/{name}/filesystemlist": { - "get": { - "description": "Get list of active filesystems on guest machine via guest agent", -@@ -9024,6 +9085,67 @@ - } - ] - }, -+ "/apis/subresources.kubevirt.io/v1/namespaces/{namespace}/virtualmachines/{name}/evacuatecancel": { -+ "put": { -+ "description": "Cancel evacuation Virtual Machine", -+ "consumes": [ -+ "*/*" -+ ], -+ "operationId": "v1vm-evacuatecancel", -+ "parameters": [ -+ { -+ "name": "body", -+ "in": "body", -+ "required": true, -+ "schema": { -+ "$ref": "#/definitions/v1.EvacuateCancelOptions" -+ } -+ } -+ ], -+ "responses": { -+ "200": { -+ "description": "OK", -+ "schema": { -+ "type": "string" -+ } -+ }, -+ "400": { -+ "description": "Bad Request", -+ "schema": { -+ "type": "string" -+ } -+ }, -+ "401": { -+ "description": "Unauthorized" -+ }, -+ "404": { -+ "description": "Not Found", -+ "schema": { -+ "type": "string" -+ } -+ }, -+ "500": { -+ "description": "Internal Server Error", -+ "schema": { -+ "type": "string" -+ } -+ } -+ } -+ }, -+ "parameters": [ -+ { -+ "uniqueItems": true, -+ "type": "string", -+ "description": "Name of the resource", -+ "name": "name", -+ "in": "path", -+ "required": true -+ }, -+ { -+ "$ref": "#/parameters/namespace-nfszEHZ0" -+ } -+ ] -+ }, - "/apis/subresources.kubevirt.io/v1/namespaces/{namespace}/virtualmachines/{name}/expand-spec": { - "get": { - "description": "Get VirtualMachine object with expanded instancetype and preference.", -@@ -9723,6 +9845,67 @@ - } - ] - }, -+ "/apis/subresources.kubevirt.io/v1alpha3/namespaces/{namespace}/virtualmachineinstances/{name}/evacuatecancel": { -+ "put": { -+ "description": "Cancel evacuation Virtual Machine Instance", -+ "consumes": [ -+ "*/*" -+ ], -+ "operationId": "v1alpha3vmi-evacuatecancel", -+ "parameters": [ -+ { -+ "name": "body", -+ "in": "body", -+ "required": true, -+ "schema": { -+ "$ref": "#/definitions/v1.EvacuateCancelOptions" -+ } -+ } -+ ], -+ "responses": { -+ "200": { -+ "description": "OK", -+ "schema": { -+ "type": "string" -+ } -+ }, -+ "400": { -+ "description": "Bad Request", -+ "schema": { -+ "type": "string" -+ } -+ }, -+ "401": { -+ "description": "Unauthorized" -+ }, -+ "404": { -+ "description": "Not Found", -+ "schema": { -+ "type": "string" -+ } -+ }, -+ "500": { -+ "description": "Internal Server Error", -+ "schema": { -+ "type": "string" -+ } -+ } -+ } -+ }, -+ "parameters": [ -+ { -+ "uniqueItems": true, -+ "type": "string", -+ "description": "Name of the resource", -+ "name": "name", -+ "in": "path", -+ "required": true -+ }, -+ { -+ "$ref": "#/parameters/namespace-nfszEHZ0" -+ } -+ ] -+ }, - "/apis/subresources.kubevirt.io/v1alpha3/namespaces/{namespace}/virtualmachineinstances/{name}/filesystemlist": { - "get": { - "description": "Get list of active filesystems on guest machine via guest agent", -@@ -10492,6 +10675,67 @@ - } - ] - }, -+ "/apis/subresources.kubevirt.io/v1alpha3/namespaces/{namespace}/virtualmachines/{name}/evacuatecancel": { -+ "put": { -+ "description": "Cancel evacuation Virtual Machine", -+ "consumes": [ -+ "*/*" -+ ], -+ "operationId": "v1alpha3vm-evacuatecancel", -+ "parameters": [ -+ { -+ "name": "body", -+ "in": "body", -+ "required": true, -+ "schema": { -+ "$ref": "#/definitions/v1.EvacuateCancelOptions" -+ } -+ } -+ ], -+ "responses": { -+ "200": { -+ "description": "OK", -+ "schema": { -+ "type": "string" -+ } -+ }, -+ "400": { -+ "description": "Bad Request", -+ "schema": { -+ "type": "string" -+ } -+ }, -+ "401": { -+ "description": "Unauthorized" -+ }, -+ "404": { -+ "description": "Not Found", -+ "schema": { -+ "type": "string" -+ } -+ }, -+ "500": { -+ "description": "Internal Server Error", -+ "schema": { -+ "type": "string" -+ } -+ } -+ } -+ }, -+ "parameters": [ -+ { -+ "uniqueItems": true, -+ "type": "string", -+ "description": "Name of the resource", -+ "name": "name", -+ "in": "path", -+ "required": true -+ }, -+ { -+ "$ref": "#/parameters/namespace-nfszEHZ0" -+ } -+ ] -+ }, - "/apis/subresources.kubevirt.io/v1alpha3/namespaces/{namespace}/virtualmachines/{name}/expand-spec": { - "get": { - "description": "Get VirtualMachine object with expanded instancetype and preference.", -@@ -10999,7 +11243,7 @@ - "/healthz": { - "get": { - "description": "Health endpoint", -- "operationId": "func13", -+ "operationId": "func15", - "responses": { - "401": { - "description": "Unauthorized" -@@ -13582,6 +13826,29 @@ - } - } - }, -+ "v1.EvacuateCancelOptions": { -+ "description": "EvacuateCancelOptions may be provided on evacuate cancel request.", -+ "type": "object", -+ "properties": { -+ "apiVersion": { -+ "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", -+ "type": "string" -+ }, -+ "dryRun": { -+ "description": "When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed", -+ "type": "array", -+ "items": { -+ "type": "string", -+ "default": "" -+ }, -+ "x-kubernetes-list-type": "atomic" -+ }, -+ "kind": { -+ "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", -+ "type": "string" -+ } -+ } -+ }, - "v1.FeatureAPIC": { - "type": "object", - "properties": { -diff --git a/pkg/virt-api/api.go b/pkg/virt-api/api.go -index 6d9ccd800f..f8e85fbaf2 100644 ---- a/pkg/virt-api/api.go -+++ b/pkg/virt-api/api.go -@@ -81,11 +81,11 @@ import ( - - const ( - // Default port that virt-api listens on. -- defaultPort = 443 -+ defaultPort = 443 - defaultMetricsPort = 8080 - - // Default address that virt-api listens on. -- defaultHost = "0.0.0.0" -+ defaultHost = "0.0.0.0" - defaultMetricsHost = defaultHost - - DefaultConsoleServerPort = 8186 -@@ -581,6 +581,30 @@ func (app *virtAPIApp) composeSubresources() { - Returns(http.StatusOK, "OK", ""). - Returns(http.StatusBadRequest, httpStatusBadRequestMessage, "")) - -+ subws.Route(subws.PUT(definitions.NamespacedResourcePath(subresourcesvmGVR)+definitions.SubResourcePath("evacuatecancel")). -+ To(subresourceApp.EvacuateCancelHandler(subresourceApp.FetchVirtualMachineInstanceForVM)). -+ Consumes(mime.MIME_ANY). -+ Reads(v1.EvacuateCancelOptions{}). -+ Param(definitions.NamespaceParam(subws)).Param(definitions.NameParam(subws)). -+ Operation(version.Version+"vm-evacuatecancel"). -+ Doc("Cancel evacuation Virtual Machine"). -+ Returns(http.StatusOK, "OK", ""). -+ Returns(http.StatusNotFound, httpStatusNotFoundMessage, ""). -+ Returns(http.StatusBadRequest, httpStatusBadRequestMessage, ""). -+ Returns(http.StatusInternalServerError, httpStatusInternalServerError, "")) -+ -+ subws.Route(subws.PUT(definitions.NamespacedResourcePath(subresourcesvmiGVR)+definitions.SubResourcePath("evacuatecancel")). -+ To(subresourceApp.EvacuateCancelHandler(subresourceApp.FetchVirtualMachineInstance)). -+ Consumes(mime.MIME_ANY). -+ Reads(v1.EvacuateCancelOptions{}). -+ Param(definitions.NamespaceParam(subws)).Param(definitions.NameParam(subws)). -+ Operation(version.Version+"vmi-evacuatecancel"). -+ Doc("Cancel evacuation Virtual Machine Instance"). -+ Returns(http.StatusOK, "OK", ""). -+ Returns(http.StatusNotFound, httpStatusNotFoundMessage, ""). -+ Returns(http.StatusBadRequest, httpStatusBadRequestMessage, ""). -+ Returns(http.StatusInternalServerError, httpStatusInternalServerError, "")) -+ - // Return empty api resource list. - // K8s expects to be able to retrieve a resource list for each aggregated - // app in order to discover what resources it provides. Without returning -@@ -651,6 +675,10 @@ func (app *virtAPIApp) composeSubresources() { - Name: "virtualmachines/expand-spec", - Namespaced: true, - }, -+ { -+ Name: "virtualmachines/evacuatecancel", -+ Namespaced: true, -+ }, - { - Name: "virtualmachineinstances/guestosinfo", - Namespaced: true, -@@ -687,6 +715,10 @@ func (app *virtAPIApp) composeSubresources() { - Name: "virtualmachineinstances/sev/injectlaunchsecret", - Namespaced: true, - }, -+ { -+ Name: "virtualmachineinstances/evacuatecancel", -+ Namespaced: true, -+ }, - } - - response.WriteAsJson(list) -diff --git a/pkg/virt-api/rest/evacuate-cancel.go b/pkg/virt-api/rest/evacuate-cancel.go -new file mode 100644 -index 0000000000..63c39a0aa3 ---- /dev/null -+++ b/pkg/virt-api/rest/evacuate-cancel.go -@@ -0,0 +1,64 @@ -+package rest -+ -+import ( -+ "context" -+ "fmt" -+ "io" -+ "net/http" -+ -+ "github.com/emicklei/go-restful/v3" -+ "k8s.io/apimachinery/pkg/api/errors" -+ k8smetav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -+ "k8s.io/apimachinery/pkg/types" -+ "k8s.io/apimachinery/pkg/util/yaml" -+ v1 "kubevirt.io/api/core/v1" -+ "kubevirt.io/client-go/log" -+ -+ "kubevirt.io/kubevirt/pkg/apimachinery/patch" -+) -+ -+func (app *SubresourceAPIApp) EvacuateCancelHandler(fetcher vmiFetcher) restful.RouteFunction { -+ return func(request *restful.Request, response *restful.Response) { -+ name := request.PathParameter("name") -+ namespace := request.PathParameter("namespace") -+ -+ vmi, statusErr := fetcher(namespace, name) -+ if statusErr != nil { -+ writeError(statusErr, response) -+ return -+ } -+ -+ if vmi.Status.EvacuationNodeName == "" { -+ writeError(errors.NewBadRequest(fmt.Sprintf("vmi %s/%s is not evacuated", namespace, name)), response) -+ return -+ } -+ -+ opts := &v1.EvacuateCancelOptions{} -+ if request.Request.Body != nil { -+ defer request.Request.Body.Close() -+ err := yaml.NewYAMLOrJSONDecoder(request.Request.Body, 1024).Decode(opts) -+ switch err { -+ case io.EOF, nil: -+ break -+ default: -+ writeError(errors.NewBadRequest(fmt.Sprintf(unmarshalRequestErrFmt, err)), response) -+ return -+ } -+ } -+ -+ patchBytes, err := patch.GenerateTestReplacePatch("/status/evacuationNodeName", vmi.Status.EvacuationNodeName, "") -+ if err != nil { -+ writeError(errors.NewInternalError(err), response) -+ return -+ } -+ -+ _, err = app.virtCli.VirtualMachineInstance(namespace).Patch(context.Background(), vmi.GetName(), types.JSONPatchType, patchBytes, k8smetav1.PatchOptions{DryRun: opts.DryRun}) -+ if err != nil { -+ log.Log.Object(vmi).V(2).Reason(err).Info("Failed to patching VMI") -+ writeError(errors.NewInternalError(err), response) -+ return -+ } -+ -+ response.WriteHeader(http.StatusOK) -+ } -+} -diff --git a/staging/src/kubevirt.io/api/core/v1/deepcopy_generated.go b/staging/src/kubevirt.io/api/core/v1/deepcopy_generated.go -index 7372b22a9a..dc7c448650 100644 ---- a/staging/src/kubevirt.io/api/core/v1/deepcopy_generated.go -+++ b/staging/src/kubevirt.io/api/core/v1/deepcopy_generated.go -@@ -1407,6 +1407,28 @@ func (in *EphemeralVolumeSource) DeepCopy() *EphemeralVolumeSource { - return out - } - -+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -+func (in *EvacuateCancelOptions) DeepCopyInto(out *EvacuateCancelOptions) { -+ *out = *in -+ out.TypeMeta = in.TypeMeta -+ if in.DryRun != nil { -+ in, out := &in.DryRun, &out.DryRun -+ *out = make([]string, len(*in)) -+ copy(*out, *in) -+ } -+ return -+} -+ -+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EvacuateCancelOptions. -+func (in *EvacuateCancelOptions) DeepCopy() *EvacuateCancelOptions { -+ if in == nil { -+ return nil -+ } -+ out := new(EvacuateCancelOptions) -+ in.DeepCopyInto(out) -+ return out -+} -+ - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. - func (in *FeatureAPIC) DeepCopyInto(out *FeatureAPIC) { - *out = *in -diff --git a/staging/src/kubevirt.io/api/core/v1/types.go b/staging/src/kubevirt.io/api/core/v1/types.go -index 403a28610e..fe861ba646 100644 ---- a/staging/src/kubevirt.io/api/core/v1/types.go -+++ b/staging/src/kubevirt.io/api/core/v1/types.go -@@ -2239,6 +2239,19 @@ type MigrateOptions struct { - DryRun []string `json:"dryRun,omitempty" protobuf:"bytes,1,rep,name=dryRun"` - } - -+// EvacuateCancelOptions may be provided on evacuate cancel request. -+type EvacuateCancelOptions struct { -+ metav1.TypeMeta `json:",inline"` -+ // When present, indicates that modifications should not be -+ // persisted. An invalid or unrecognized dryRun directive will -+ // result in an error response and no further processing of the -+ // request. Valid values are: -+ // - All: all dry run stages will be processed -+ // +optional -+ // +listType=atomic -+ DryRun []string `json:"dryRun,omitempty" protobuf:"bytes,1,rep,name=dryRun"` -+} -+ - // VirtualMachineInstanceGuestAgentInfo represents information from the installed guest agent - // - // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object -diff --git a/staging/src/kubevirt.io/api/core/v1/types_swagger_generated.go b/staging/src/kubevirt.io/api/core/v1/types_swagger_generated.go -index 728136ed63..3ef31eae5d 100644 ---- a/staging/src/kubevirt.io/api/core/v1/types_swagger_generated.go -+++ b/staging/src/kubevirt.io/api/core/v1/types_swagger_generated.go -@@ -613,6 +613,13 @@ func (MigrateOptions) SwaggerDoc() map[string]string { - } - } - -+func (EvacuateCancelOptions) SwaggerDoc() map[string]string { -+ return map[string]string{ -+ "": "EvacuateCancelOptions may be provided on evacuate cancel request.", -+ "dryRun": "When present, indicates that modifications should not be\npersisted. An invalid or unrecognized dryRun directive will\nresult in an error response and no further processing of the\nrequest. Valid values are:\n- All: all dry run stages will be processed\n+optional\n+listType=atomic", -+ } -+} -+ - func (VirtualMachineInstanceGuestAgentInfo) SwaggerDoc() map[string]string { - return map[string]string{ - "": "VirtualMachineInstanceGuestAgentInfo represents information from the installed guest agent\n\n+k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object", -diff --git a/staging/src/kubevirt.io/client-go/api/openapi_generated.go b/staging/src/kubevirt.io/client-go/api/openapi_generated.go -index b982b1620c..2cc9306a85 100644 ---- a/staging/src/kubevirt.io/client-go/api/openapi_generated.go -+++ b/staging/src/kubevirt.io/client-go/api/openapi_generated.go -@@ -374,6 +374,7 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA - "kubevirt.io/api/core/v1.EFI": schema_kubevirtio_api_core_v1_EFI(ref), - "kubevirt.io/api/core/v1.EmptyDiskSource": schema_kubevirtio_api_core_v1_EmptyDiskSource(ref), - "kubevirt.io/api/core/v1.EphemeralVolumeSource": schema_kubevirtio_api_core_v1_EphemeralVolumeSource(ref), -+ "kubevirt.io/api/core/v1.EvacuateCancelOptions": schema_kubevirtio_api_core_v1_EvacuateCancelOptions(ref), - "kubevirt.io/api/core/v1.FeatureAPIC": schema_kubevirtio_api_core_v1_FeatureAPIC(ref), - "kubevirt.io/api/core/v1.FeatureHyperv": schema_kubevirtio_api_core_v1_FeatureHyperv(ref), - "kubevirt.io/api/core/v1.FeatureKVM": schema_kubevirtio_api_core_v1_FeatureKVM(ref), -@@ -18909,6 +18910,53 @@ func schema_kubevirtio_api_core_v1_EphemeralVolumeSource(ref common.ReferenceCal - } - } - -+func schema_kubevirtio_api_core_v1_EvacuateCancelOptions(ref common.ReferenceCallback) common.OpenAPIDefinition { -+ return common.OpenAPIDefinition{ -+ Schema: spec.Schema{ -+ SchemaProps: spec.SchemaProps{ -+ Description: "EvacuateCancelOptions may be provided on evacuate cancel request.", -+ Type: []string{"object"}, -+ Properties: map[string]spec.Schema{ -+ "kind": { -+ SchemaProps: spec.SchemaProps{ -+ Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", -+ Type: []string{"string"}, -+ Format: "", -+ }, -+ }, -+ "apiVersion": { -+ SchemaProps: spec.SchemaProps{ -+ Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", -+ Type: []string{"string"}, -+ Format: "", -+ }, -+ }, -+ "dryRun": { -+ VendorExtensible: spec.VendorExtensible{ -+ Extensions: spec.Extensions{ -+ "x-kubernetes-list-type": "atomic", -+ }, -+ }, -+ SchemaProps: spec.SchemaProps{ -+ Description: "When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed", -+ Type: []string{"array"}, -+ Items: &spec.SchemaOrArray{ -+ Schema: &spec.Schema{ -+ SchemaProps: spec.SchemaProps{ -+ Default: "", -+ Type: []string{"string"}, -+ Format: "", -+ }, -+ }, -+ }, -+ }, -+ }, -+ }, -+ }, -+ }, -+ } -+} -+ - func schema_kubevirtio_api_core_v1_FeatureAPIC(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ diff --git a/images/virt-artifact/patches/README.md b/images/virt-artifact/patches/README.md deleted file mode 100644 index fb33a4ae15..0000000000 --- a/images/virt-artifact/patches/README.md +++ /dev/null @@ -1,325 +0,0 @@ -# Patches - -#### `005-prevent-permanent-patching-of-services.patch` - -Fix patching of Services during each reconcile: - -``` -{"component":"virt-operator","level":"info","msg":"service kubevirt-prometheus-metrics patched","pos":"core.go:142","timestamp":"2024-07-09T16:03:18.136326Z"} -{"component":"virt-operator","level":"info","msg":"service virt-api patched","pos":"core.go:142","timestamp":"2024-07-09T16:03:18.138751Z"} -{"component":"virt-operator","level":"info","msg":"service kubevirt-operator-webhook patched","pos":"core.go:142","timestamp":"2024-07-09T16:03:18.140853Z"} -{"component":"virt-operator","level":"info","msg":"service virt-exportproxy patched","pos":"core.go:142","timestamp":"2024-07-09T16:03:18.142806Z"} -``` - -#### `007-tolerations-for-strategy-dumper-job.patch` - -There is a problem when all nodes in cluster have taints, KubeVirt can't run virt-operator-strategy-dumper job. -The provided fix will always run the job in same place where virt-operator runs - -- https://github.com/kubevirt/kubevirt/pull/9360 - -#### `011-virt-api-authentication.patch` -Added the ability for virt-api to authenticate clients with certificates signed by our rootCA located in the config-map virtualization-ca. - -#### `012-support-kubeconfig-env.patch` -Support `KUBECONFIG` environment variable. - -#### `013-virt-api-rate-limiter.patch` -A patch has been added to enable the configuration of the rate limiter via the environment variables VIRT_API_RATE_LIMITER_QPS and VIRT_API_RATE_LIMITER_BURST. - -#### `014-delete-apiserver.patch` -Do not create Kubevirt APIService. - -#### `015-rename-core-resources.patch` -Replace "kubevirt" with "kubevirt-internal-virtualziation" in the core resource names. - -#### `016-rename-install-strategy-labels.patch` - -Rename kubevirt.io/install-strategy-registry labels to install.internal.virtualization.deckhouse.io/install-strategy-registry. -Rename app.kubernetes.io/managed-b value from virt-operator to virt-operator-internal-virtualization. - -Rewrite these labels with patch, because strategy generator Job starts without kube-api-rewriter. - -#### `017-fix-vmi-subresource-url.patch` - -Use virtualization-api instead subresources.kubevirt.io for vmi operations. - -#### `018-rename-devices-kubevirt-io.patch` - -Rename additional resources previded with Device Plugin API to not overlap with original Kubevirt. - -Rename unix-socket path used for register devices. - -#### `019-remove-deprecation-warnings-from-crds.patch` - -Virtualization-controller doesn't use deprecated apiGroup versions. Deprecation warnings are distracting in our case. - -#### `020-stop-managing-kvvm-kvvmi-crds.patch` - -Stop managing VirtualMachine and VirtualMachineInstance CRDs with virt-operator. Module will install this CRDs using Helm. - -#### `021-support-qcow2-for-filesystem.patch` - -Support format qcow2 for pvc with filesystem mode. - -When generating XML for libvirt, we utilize converters that translate the virtual machine instance specification into a Domain. We're making a slight adjustment to this process. -We're changing the raw format for disks to qcow2 for all images created on the file system. These values are hardcoded as we can't determine the disk format used by the virtual machine through qemu-img. -Additionally, kubevirt can create images on an empty PVC. We're changing this behavior as well, altering the format of the created disk to qcow2. This is achieved using qemu-img. - -#### `022-cleanup-error-pods.patch` - -Cleanup stale Pods owned by the VMI, keep only last 3 in the Failed phase. - -Why we need it? - -Unsuccessful migrations may leave a lot of Pods. These huge lists reduce performance on virtualization-controller and cdi-deployment restarts. - -#### `023-replace-expressions-for-validating-admission-policy.patch` - -Replace the expressions for the ValidatingAdmissionPolicy kubevirt-node-restriction-policy. -This is necessary because of the kube-api-rewriter that changes the labels. - -#### `024-cover-kubevirt-metrics.patch` - -Configure kubevirt's components metrics web servers to listen on localhost. -This is necessary for ensuring that the metrics can be accessed only by Prometheus via kube-rbac-proxy sidecar. - -Currently covered metrics: -- virt-handler -- virt-controller -- virt-api - -#### `025-stream-graceful-shutdown.patch` - -Graceful termination of websocket connection for serial console and vnc connections. - -#### `026-add-healthz-to-virt-operator.patch` - -Add separate healthz endpoint to virt-operator. - -#### `027-auto-migrate-if-nodeplacement-changed.patch` - -Start the migration if the nodeSelector or affinity has changed. -How does it work? -1. When changing the affinity or nodeSelector in the vm, the vm controller updates the vmi specification. -2. When changing the affinity or nodeSelector in vmi, the vmi controller will set the `NodePlacementNotMatched` condition to True in vmi. -3. The workload-updater controller monitors the vmi and starts migration when there is a `NodePlacementNotMatched` conditions on the vmi. -4. When the migration is completed, virt-handler will remove the condition `NodePlacementNotMatched` from the vmi - -#### `028-inject-placement-anynode.patch` - -By default, the virtual-operator adds a nodePlacement with the RequireControlPlanePreferNonWorker. -But we set up the placement ourselves, so we replace the policy with AnyNode. - -#### `029-use-OFVM_CODE-for-linux.patch` - -Kubevirt uses OVFM_CODE.secboot.fd in 2 combinations: OVFM_CODE.secboot.fd + OVFM_VARS.secboot.fd when secboot is enabled and OVFM_CODE.secboot.fd + OVFM_VARS.fd when secboot is disabled. -It works fine with original CentOS based virt-launcher in both secboot modes. -We use ALTLinux based virt-launcher, and it fails to start Linux VM with more than 12 CPUs in secboot disabled mode. - -Kubevirt uses flags to detect firmware combinations in converter. -EFIConfiguration, so we can't set needed files directly. -But there is combination for SEV: OVFM_CODE.cc.fd + OVMF_VARS.fd that works for Linux, because OVFM_CODE.cc.fd is actually a symlink to OVFM_CODE.fd. -So, we set true for the second flag to force OVFM_CODE.cc.fd + OVMF_VARS.fd for non-Windows virtual machines._ - -#### `030-prevent-adding-node-selector-for-dvp-generic-cpu-model.patch` - -- Do not add cpu-model nodeSelector for "kvm64" model. This selector prevents starting VMs as node-labeler ignores to labeling nodes with "kvm64" model. - -- Overwrite calculated model on migration, put back "kvm64" for Discovery and Features vmclass types. - -#### `031-hotplug-container-disk.patch` - -Add Hotplug container-disk volumes. -How `container-disk` and HotPlug Work -The `container-disk` is a program written in C used within KubeVirt to facilitate the mounting of container-based disk images into virtual machines. Its core function is to start up and create a UNIX socket within a specific directory. The program terminates when the socket is removed or upon receiving a `SIGTERM` signal. - -##### Key Workflow: `container-disk` - -##### Initialization -- A sidecar container, running the `container-disk` image, is created alongside the `virt-launcher` pod. -- An init-container in the `virt-launcher` pod copies the `container-disk` program to a shared `emptyDir` volume. This setup allows the sidecar to execute the program. - -##### Socket Creation - -- The `container-disk` program creates a socket in the `emptyDir` volume. -- This shared volume allows the `virt-handler` to locate the socket on the host machine at: - `/var/lib/kubelet/pods/.../volumes/kubernetes.io~empty-dir/`. - -##### Socket Detection and Mounting - -- Upon detecting the socket, `virt-handler` identifies it as a `container-disk` volume and retrieves its parent mount point. -- For a container runtime like `containerd`, the mount point resolves to the root filesystem of the pulled image, typically at: - `/run/containerd/io.containerd.runtime.v2.task/k8s.io//rootfs/`. -- The disk image must be located at `disk/disk.img` within this filesystem and is mounted into the VM. - -## HotPlug in KubeVirt -The HotPlug mechanism allows dynamic attachment of PVCs and `container-disk` volumes to a running VM by leveraging a separate `hotplug` pod. - -### HotPlug Pod Setup -- A `hotplug` pod is created with the target PVCs mounted into an `emptyDir` volume under the `/hp` directory. -- The `container-disk` program runs in the `hotplug` pod to create the necessary sockets for these volumes. - -### Volume Detection and Mounting -- The `virt-handler` locates the sockets on the host system at: - `/var/lib/kubelet/pods//volumes/empty-dir/hp-disks/...`. -- For block devices, `virt-handler` creates a block device on the VM using `mknodat`. -- For file systems, the volume is mounted as a file. - -### Unmounting -- The unmount process is identical to that of `hotplug PVCs`. -- The `emptyDir` resources are retained and cleaned up later by Kubernetes. - -#### `032-fix-virt-controller-tests.patch` - -Fix unit tests for virt-controller. - -```shell -# Use to run tests: -ginkgo -succinct /home/dmitrii/Base/Flant/kubevirt/pkg/virt-controller/... -``` - -#### `033-manage-pods-network-priotity-during-migration-using-cilium-label.patch` - -**Problem:** -During the VM migration process, two pods with the same address are created and packets are randomly delivered to them. - -**Solution**: -To force delivery of packages to only one VM pod, the special label `network.deckhouse.io/pod-common-ip-priority` were added. -The label allows setting the priority of pod for cilium relative to other pods with the same IP address. -Network traffic will be directed to the pod with the higher priority. -Absence of the label means the lowest priority (pod with a network priority label is more prioritized than a pod without a label). -The lower the numerical value, the higher the priority. - -**How does it work?** -1. When migration starts, the source pod receives a decreased network priority ("1"). -2. The target pod is immediately created with the lowest network priority ("2"). -3. When the virtual machine is suspended for offline migration, the target pod receives the highest network priority ("0"), - while the source pod retains its decreased priority ("1"). - -Thus, packets are delivered as expected: initially only to the source pod during migration, and after migration completes, only to the target pod. - -#### `034-allow-update-kvvmi-for-virtualization-sas.patch` - -By default, the KVVMI spec can update only KubeVirt service accounts. This patch adds our virtualization accounts to the allowed list. -(`virtualization-controller`, `virtualization-api`) - -#### `035-allow-change-serial-on-kvvmi.patch` - -By default, the disk specification is immutable, but for backward compatibility, we need to allow modifying the serial. - -#### `036-enhance-SCSI-disk-serial-validation.patch` - -**Related Issue:** [#13858](https://github.com/kubevirt/kubevirt/issues/13858) -**Pull Request:** [#13859](https://github.com/kubevirt/kubevirt/pull/13859) - -##### What this PR does -- **Before:** A virtual machine (VM) launched by QEMU could fail if a disk's serial number exceeded 36 characters, as QEMU enforces this limit. KubeVirt did not validate this beforehand, leading to runtime errors. -- **After:** - - The API now validates disk serial numbers, preventing users from setting values longer than 36 characters and avoiding VM startup failures in QEMU. - - For existing VMs, serial numbers exceeding this limit will be automatically truncated to maintain backward compatibility. - -##### Why this change? -This update ensures compatibility with recent QEMU changes and prevents runtime errors by enforcing validation at the API level while preserving support for existing VMs through automatic serial number truncation. - -#### `037-set-ReadOnlyRootFilesystem-to-virt-launcher.patch` -To enhance security, this patch enables ReadOnlyRootFilesystem for the virt-launcher compute pod. -Since libvirt and QEMU require writable directories, five emptyDir volumes are added and mounted to: -- /var/run -- /var/log -- /etc/libvirt -- /var/lib/libvirt/ -- /var/cache/libvirt -- /var/lib/swtpm-localca -- /tmp - -This ensures compatibility while maintaining a read-only root filesystem for improved isolation and security. - -#### `038-disable-unnecessary-libvirt-sockets.patch` - -This patch disables unnecessary libvirt sockets by running `virtqemud` and `virtlogd` with additional flags to prevent their creation. Specifically, we disable the admin and read-only servers: - -- `--no-admin-srv` and `--no-ro-srv` flags for `virtqemud`. -- `--no-admin-srv` flag for `virtlogd`. - -By using these flags, the following sockets are not created in the first place: - -- `/var/run/libvirt/virtlogd-admin-sock` -- `/var/run/libvirt/virtqemud-admin-sock` -- `/var/run/libvirt/virtqemud-sock-ro` - -This ensures a cleaner runtime environment, reducing unnecessary components and preventing unintended interactions, without affecting libvirt's core functionality. - -##### Dependency - -This patch depends on the [001-disable-ro-and-admin-servers.patch](../../libvirt/patches/001-disable-ro-and-admin-servers.patch) for proper flag application to disable the relevant servers and prevent the creation of their associated sockets. - -#### `039-get-applied-checksum.patch` - -This patch introduces the GetAppliedChecksum() method in virt-launcher. - -virt-handler now tracks synchronized VMIs and computes their checksums. Periodically, it queries virt-launcher for the applied checksum. This ensures that we have two checksums: - -The last one sent for synchronization. -The one actually applied. -Storing these checksums in VMI annotations helps verify that spec changes were pushed by virt-handler and not by an attacker. - -#### `040-set-reboot-policy.patch` - -This patch modifies the behavior of domain reboot actions in virt-launcher by overriding the default reboot policy. - -### Changes Introduced: -- Registers a QEMU monitor shutdown event callback to handle shutdown events. -- Sends a QEMU agent command to override the reboot action, changing it from `reboot` to `shutdown`. -- Logs shutdown events and writes them to `/dev/termination-log`. -- Ensures that domain shutdown events are captured and processed correctly. - -#### `041-rename-node-labeller-virt-launcher-init.patch` - -This patch modifies init container args in virt-launcher images from node-labeller.sh to node-labeller. -This bash script has been rewritten to golang. - -#### `042-restrict-libvirt-socket-to-qemu.patch` - -This patch enhances security by ensuring that `virtqemud` only accepts connections from its corresponding process. It achieves this by using the `LIBVIRT_UNIX_SOCKET_AUTH_PID` environment variable, which restricts access to the process ID (PID) of the `virt-launcher` process that started `virtqemud`. - -#### `043-add-qemu-and-libvirt-versions` - -This path adds annotations to the VMI with the versions of libvirt and qemu used to create the VMI. - -##### Changes -- Configures `virtqemud` to use the `LIBVIRT_UNIX_SOCKET_AUTH_PID` environment variable, restricting access to the `virt-launcher` process. -- Ensures that `virtqemud` only accepts connections from the process that initiated it. -- Prevents unauthorized processes from accessing the libvirt socket, reducing security risks and the potential for privilege escalation. -- Updates the migration mechanism: since virt-handler directly connects to the `virtqemud` socket during migration, the libvirt patch does not authorize it. To address this issue, an additional `migration-proxy` has been introduced in `virt-launcher`. This proxy receives traffic from `virt-handler` and forwards it to `virtqemud`. -- A new gRPC call, MigrationProxy, has been added to start this migration proxy. - -##### Dependency -This patch depends on the [002-auth-pid-restriction.patch](../../libvirt/patches/002-auth-pid-restriction.patch) in libvirt, which introduces the `LIBVIRT_UNIX_SOCKET_AUTH_PID` environment variable to restrict socket access based on PID. - -#### `044-disable-workload-updater.patch` -This patch disables controller workload-updater in kubevirt. -We have our implementation in virtualization-controller. - -#### `045-virt-launcher-image-holder-command-sleep.patch` - -This patch modifies virt-launcher-image-holder command from `sh -c "sleep infinity"` to `sleep infinity`. - -#### `046-hotplug-attachment-trigger-pod-remove-bash.patch` - -This patch modifies init container by removing sh and bash util and replcae commands. -- Init container tempPod change command from `"/bin/bash", "-c", "echo", "bound PVCs"` and `"/bin/bash","-c","exit", "0"` to static binary `temp_pod`. -- HotplugAttachmentPod change command from `"/bin/sh", "-c", "/usr/bin/container-disk --copy-path /path/hp"` to `"/usr/bin/container-disk", "--copy-path", "/path/hp"` - -Also fixed vmi_test.go, replace `Equal("/bin/bash -c echo bound PVCs")` to `Equal("temp_pod")`, - -#### `047-node-labeller-replace-sysctl-command-with-readfile.patch` - -This patch modifies function `isNodeRealtimeCapable` in `node_labeller.go`, replacing linux util `sysctl` to `os.ReadFile("/proc/sys/kernel/sched_rt_runtime_us")` - -#### `048-disable-evacuation-controller.patch` -This patch disables evacuation controller in kubevirt. -We have our implementation in virtualization-controller. - -#### `049-implement-evacuate-cancel-subresource.patch` -This patch implement evacuate-cancel subresource. diff --git a/images/virt-artifact/werf.inc.yaml b/images/virt-artifact/werf.inc.yaml index b541c06774..84458aaf45 100644 --- a/images/virt-artifact/werf.inc.yaml +++ b/images/virt-artifact/werf.inc.yaml @@ -1,6 +1,7 @@ --- # Source https://github.com/kubevirt/kubevirt/blob/v1.3.1/hack/dockerized#L15 -{{- $version := "1.3.1" }} +{{- $version := "v1.3.1" }} +{{- $tag := print $version "-virtualization/v1"}} {{- $goVersion := "1.22.7" }} {{- $name := print $.ImageName "-dependencies" -}} @@ -32,16 +33,6 @@ fromImage: base-alt-p11 mount: - fromPath: ~/go-pkg-cache to: /go/pkg -git: - - add: /images/{{ $.ImageName }} - to: / - stageDependencies: - install: - - '**/*' - includePaths: - - patches - excludePaths: - - patches/README.md shell: beforeInstall: - apt-get update @@ -52,13 +43,8 @@ shell: - rm --recursive --force /var/lib/apt/lists/ftp.altlinux.org* /var/cache/apt/*.bin install: - - git clone --depth 1 --branch v{{ $version }} {{ $.SOURCE_REPO }}/kubevirt/kubevirt.git /kubevirt + - git clone --depth 1 --branch {{ $tag }} {{ $.SOURCE_REPO }}/deckhouse/3p-kubevirt.git /kubevirt - cd /kubevirt - - | - for p in /patches/*.patch ; do - echo -n "Apply ${p} ... " - git apply --ignore-space-change --ignore-whitespace ${p} && echo OK || (echo FAIL ; exit 1) - done - go mod edit -go={{ $goVersion }} - go mod download - |