diff --git a/0001-feat-pass-timeout-from-virt-monitor-to-virt-tail.patch b/0001-feat-pass-timeout-from-virt-monitor-to-virt-tail.patch new file mode 100644 index 0000000..cb1fb43 --- /dev/null +++ b/0001-feat-pass-timeout-from-virt-monitor-to-virt-tail.patch @@ -0,0 +1,128 @@ +From 0db64ad662f3be98e503cc00c1b96cadbf01dbf5 Mon Sep 17 00:00:00 2001 +From: YuJack +Date: Mon, 23 Dec 2024 12:25:34 +0800 +Subject: [PATCH] feat: pass timeout from virt-monitor to virt-tail + +Signed-off-by: YuJack +Signed-off-by: Caleb Crane +--- + cmd/virt-tail/main.go | 22 +++++++++++-------- + .../services/serialconsolelog.go | 4 ++-- + pkg/virt-controller/services/template.go | 6 +++-- + 3 files changed, 19 insertions(+), 13 deletions(-) + +diff --git a/cmd/virt-tail/main.go b/cmd/virt-tail/main.go +index 3cd16d6b1f..faa652d83e 100644 +--- a/cmd/virt-tail/main.go ++++ b/cmd/virt-tail/main.go +@@ -40,6 +40,9 @@ import ( + "kubevirt.io/client-go/log" + ) + ++// initial timeout for serial console socket creation ++const initialSocketTimeout = time.Second * 20 ++ + type TermFileError struct{} + type SocketFileError struct{} + +@@ -52,9 +55,10 @@ func (m *SocketFileError) Error() string { + } + + type VirtTail struct { +- ctx context.Context +- logFile string +- g *errgroup.Group ++ ctx context.Context ++ logFile string ++ g *errgroup.Group ++ socketTimeout *time.Duration + } + + func (v *VirtTail) checkFile(socketFile string) bool { +@@ -134,10 +138,8 @@ func (v *VirtTail) watchFS() error { + return err + } + +- // initial timeout for serial console socket creation +- const initialSocketTimeout = time.Second * 20 + socketCheckCh := make(chan int) +- time.AfterFunc(initialSocketTimeout, func() { ++ time.AfterFunc(*v.socketTimeout, func() { + socketCheckCh <- 1 + }) + +@@ -195,6 +197,7 @@ func main() { + pflag.CommandLine.AddGoFlag(goflag.CommandLine.Lookup("v")) + pflag.CommandLine.ParseErrorsWhitelist = pflag.ParseErrorsWhitelist{UnknownFlags: true} + logFile := pflag.String("logfile", "", "path of the logfile to be streamed") ++ socketTimeout := pflag.Duration("socket-timeout", initialSocketTimeout, "Amount of time to wait for qemu") + pflag.Parse() + + log.InitializeLogging("virt-tail") +@@ -212,9 +215,10 @@ func main() { + g, gctx := errgroup.WithContext(ctx) + + v := &VirtTail{ +- ctx: gctx, +- logFile: *logFile, +- g: g, ++ ctx: gctx, ++ logFile: *logFile, ++ socketTimeout: socketTimeout, ++ g: g, + } + + g.Go(v.tailLogs) +diff --git a/pkg/virt-controller/services/serialconsolelog.go b/pkg/virt-controller/services/serialconsolelog.go +index ea6463e4d3..de9ec6f9b5 100644 +--- a/pkg/virt-controller/services/serialconsolelog.go ++++ b/pkg/virt-controller/services/serialconsolelog.go +@@ -13,7 +13,7 @@ import ( + virtconfig "kubevirt.io/kubevirt/pkg/virt-config" + ) + +-func generateSerialConsoleLogContainer(vmi *v1.VirtualMachineInstance, image string, config *virtconfig.ClusterConfig, virtLauncherLogVerbosity uint) *k8sv1.Container { ++func generateSerialConsoleLogContainer(vmi *v1.VirtualMachineInstance, image string, config *virtconfig.ClusterConfig, virtLauncherLogVerbosity uint, socketTimeout string) *k8sv1.Container { + const serialPort = 0 + if isSerialConsoleLogEnabled(vmi, config) { + logFile := fmt.Sprintf("%s/%s/virt-serial%d-log", util.VirtPrivateDir, vmi.ObjectMeta.UID, serialPort) +@@ -25,7 +25,7 @@ func generateSerialConsoleLogContainer(vmi *v1.VirtualMachineInstance, image str + Image: image, + ImagePullPolicy: k8sv1.PullIfNotPresent, + Command: []string{"/usr/bin/virt-tail"}, +- Args: []string{"--logfile", logFile}, ++ Args: []string{"--logfile", logFile, "--socket-timeout", socketTimeout}, + VolumeMounts: []k8sv1.VolumeMount{ + k8sv1.VolumeMount{ + Name: "private", +diff --git a/pkg/virt-controller/services/template.go b/pkg/virt-controller/services/template.go +index a0f1b3a8d6..b980fd06e5 100644 +--- a/pkg/virt-controller/services/template.go ++++ b/pkg/virt-controller/services/template.go +@@ -398,6 +398,8 @@ func (t *templateService) renderLaunchManifest(vmi *v1.VirtualMachineInstance, i + } + + var command []string ++ var qemuTimeout = generateQemuTimeoutWithJitter(t.launcherQemuTimeout) ++ + if tempPod { + logger := log.DefaultLogger() + logger.Infof("RUNNING doppleganger pod for %s", vmi.Name) +@@ -406,7 +408,7 @@ func (t *templateService) renderLaunchManifest(vmi *v1.VirtualMachineInstance, i + "echo", "bound PVCs"} + } else { + command = []string{"/usr/bin/virt-launcher-monitor", +- "--qemu-timeout", generateQemuTimeoutWithJitter(t.launcherQemuTimeout), ++ "--qemu-timeout", qemuTimeout, + "--name", domain, + "--uid", string(vmi.UID), + "--namespace", namespace, +@@ -502,7 +504,7 @@ func (t *templateService) renderLaunchManifest(vmi *v1.VirtualMachineInstance, i + containers = append(containers, virtiofsContainers...) + } + +- sconsolelogContainer := generateSerialConsoleLogContainer(vmi, t.launcherImage, t.clusterConfig, virtLauncherLogVerbosity) ++ sconsolelogContainer := generateSerialConsoleLogContainer(vmi, t.launcherImage, t.clusterConfig, virtLauncherLogVerbosity, qemuTimeout) + if sconsolelogContainer != nil { + containers = append(containers, *sconsolelogContainer) + } diff --git a/0002-Ensure-SEV-VMs-use-stateless-OVMF-firmware.patch b/0002-Ensure-SEV-VMs-use-stateless-OVMF-firmware.patch new file mode 100644 index 0000000..7d74f94 --- /dev/null +++ b/0002-Ensure-SEV-VMs-use-stateless-OVMF-firmware.patch @@ -0,0 +1,149 @@ +From 7ece048f90223e395001f9fc158c5c2af35ca520 Mon Sep 17 00:00:00 2001 +From: Vasiliy Ulyanov +Date: Wed, 10 Jul 2024 10:27:15 +0200 +Subject: [PATCH] Ensure SEV VMs use stateless OVMF firmware + +Signed-off-by: Vasiliy Ulyanov +Signed-off-by: Caleb Crane +--- + .../virtwrap/converter/converter.go | 20 ++++++++++++------- + pkg/virt-launcher/virtwrap/efi/efi.go | 11 ++++------ + pkg/virt-launcher/virtwrap/efi/efi_test.go | 8 +------- + rpm/BUILD.bazel | 2 +- + 4 files changed, 19 insertions(+), 22 deletions(-) + +diff --git a/pkg/virt-launcher/virtwrap/converter/converter.go b/pkg/virt-launcher/virtwrap/converter/converter.go +index 0565ceb5dd..8f1094d141 100644 +--- a/pkg/virt-launcher/virtwrap/converter/converter.go ++++ b/pkg/virt-launcher/virtwrap/converter/converter.go +@@ -1222,6 +1222,12 @@ func Convert_v1_Firmware_To_related_apis(vmi *v1.VirtualMachineInstance, domain + Template: c.EFIConfiguration.EFIVars, + NVRam: filepath.Join(services.PathForNVram(vmi), vmi.Name+"_VARS.fd"), + } ++ ++ if util.IsSEVVMI(vmi) { ++ // Use stateless firmware for SEV VMs ++ domain.Spec.OS.BootLoader.Type = "rom" ++ domain.Spec.OS.NVRam = nil ++ } + } + + if firmware.Bootloader != nil && firmware.Bootloader.BIOS != nil { +@@ -1449,13 +1455,13 @@ func Convert_v1_VirtualMachineInstance_To_api_Domain(vmi *v1.VirtualMachineInsta + + // Set SEV launch security parameters: https://libvirt.org/formatdomain.html#launch-security + if c.UseLaunchSecurity { +- sevPolicyBits := launchsecurity.SEVPolicyToBits(vmi.Spec.Domain.LaunchSecurity.SEV.Policy) +- // Cbitpos and ReducedPhysBits will be filled automatically by libvirt from the domain capabilities +- domain.Spec.LaunchSecurity = &api.LaunchSecurity{ +- Type: "sev", +- Policy: "0x" + strconv.FormatUint(uint64(sevPolicyBits), 16), +- DHCert: vmi.Spec.Domain.LaunchSecurity.SEV.DHCert, +- Session: vmi.Spec.Domain.LaunchSecurity.SEV.Session, ++ sevPolicyBits := launchsecurity.SEVPolicyToBits(vmi.Spec.Domain.LaunchSecurity.SEV.Policy) ++ // Cbitpos and ReducedPhysBits will be filled automatically by libvirt from the domain capabilities ++ domain.Spec.LaunchSecurity = &api.LaunchSecurity{ ++ Type: "sev", ++ Policy: "0x" + strconv.FormatUint(uint64(sevPolicyBits), 16), ++ DHCert: vmi.Spec.Domain.LaunchSecurity.SEV.DHCert, ++ Session: vmi.Spec.Domain.LaunchSecurity.SEV.Session, + } + controllerDriver = &api.ControllerDriver{ + IOMMU: "on", +diff --git a/pkg/virt-launcher/virtwrap/efi/efi.go b/pkg/virt-launcher/virtwrap/efi/efi.go +index 0a51067dc0..730b637c9f 100644 +--- a/pkg/virt-launcher/virtwrap/efi/efi.go ++++ b/pkg/virt-launcher/virtwrap/efi/efi.go +@@ -31,8 +31,7 @@ const ( + EFIVarsAARCH64 = "AAVMF_VARS.fd" + EFICodeSecureBoot = "OVMF_CODE.secboot.fd" + EFIVarsSecureBoot = "OVMF_VARS.secboot.fd" +- EFICodeSEV = "OVMF_CODE.cc.fd" +- EFIVarsSEV = EFIVars ++ EFICodeSEV = "OVMF.amdsev.fd" + ) + + type EFIEnvironment struct { +@@ -41,14 +40,13 @@ type EFIEnvironment struct { + codeSecureBoot string + varsSecureBoot string + codeSEV string +- varsSEV string + } + + func (e *EFIEnvironment) Bootable(secureBoot, sev bool) bool { + if secureBoot { + return e.varsSecureBoot != "" && e.codeSecureBoot != "" + } else if sev { +- return e.varsSEV != "" && e.codeSEV != "" ++ return e.codeSEV != "" + } else { + return e.vars != "" && e.code != "" + } +@@ -68,7 +66,8 @@ func (e *EFIEnvironment) EFIVars(secureBoot, sev bool) string { + if secureBoot { + return e.varsSecureBoot + } else if sev { +- return e.varsSEV ++ // SEV uses stateless firmware ++ return "" + } else { + return e.vars + } +@@ -100,7 +99,6 @@ func DetectEFIEnvironment(arch, ovmfPath string) *EFIEnvironment { + + // detect EFI with SEV + codeWithSEV := getEFIBinaryIfExists(ovmfPath, EFICodeSEV) +- varsWithSEV := getEFIBinaryIfExists(ovmfPath, EFIVarsSEV) + + return &EFIEnvironment{ + codeSecureBoot: codeWithSB, +@@ -108,7 +106,6 @@ func DetectEFIEnvironment(arch, ovmfPath string) *EFIEnvironment { + code: code, + vars: vars, + codeSEV: codeWithSEV, +- varsSEV: varsWithSEV, + } + } + +diff --git a/pkg/virt-launcher/virtwrap/efi/efi_test.go b/pkg/virt-launcher/virtwrap/efi/efi_test.go +index dcc0e5a6f7..1123c20abd 100644 +--- a/pkg/virt-launcher/virtwrap/efi/efi_test.go ++++ b/pkg/virt-launcher/virtwrap/efi/efi_test.go +@@ -82,7 +82,7 @@ var _ = Describe("EFI environment detection", func() { + ) + + It("SEV EFI Roms", func() { +- ovmfPath := createEFIRoms(EFICodeSEV, EFIVarsSEV) ++ ovmfPath := createEFIRoms(EFICodeSEV) + defer os.RemoveAll(ovmfPath) + + efiEnv := DetectEFIEnvironment("x86_64", ovmfPath) +@@ -98,11 +98,5 @@ var _ = Describe("EFI environment detection", func() { + Expect(efiEnv.EFICode(secureBootEnabled, !sevEnabled)).ToNot(Equal(codeSEV)) + Expect(efiEnv.EFICode(!secureBootEnabled, sevEnabled)).To(Equal(codeSEV)) + Expect(efiEnv.EFICode(!secureBootEnabled, !sevEnabled)).ToNot(Equal(codeSEV)) +- +- varsSEV := filepath.Join(ovmfPath, EFIVarsSEV) +- Expect(efiEnv.EFIVars(secureBootEnabled, sevEnabled)).ToNot(Equal(varsSEV)) +- Expect(efiEnv.EFIVars(secureBootEnabled, !sevEnabled)).ToNot(Equal(varsSEV)) +- Expect(efiEnv.EFIVars(!secureBootEnabled, sevEnabled)).To(Equal(varsSEV)) +- Expect(efiEnv.EFIVars(!secureBootEnabled, !sevEnabled)).To(Equal(varsSEV)) // same as EFIVars + }) + }) +diff --git a/rpm/BUILD.bazel b/rpm/BUILD.bazel +index 5c98670f80..13184cadb5 100644 +--- a/rpm/BUILD.bazel ++++ b/rpm/BUILD.bazel +@@ -1228,7 +1228,7 @@ rpmtree( + "/usr/sbin/iptables": "/usr/sbin/iptables-legacy", + "/usr/bin/nc": "/usr/bin/ncat", + # Create a symlink to OVMF binary with SEV support (edk2 rpm does not do that for unknown reason) +- "/usr/share/OVMF/OVMF_CODE.cc.fd": "../edk2/ovmf/OVMF_CODE.cc.fd", ++ "/usr/share/OVMF/OVMF.amdsev.fd": "../edk2/ovmf/OVMF.amdsev.fd", + }, + visibility = ["//visibility:public"], + ) +-- +2.47.1 + diff --git a/kubevirt.changes b/kubevirt.changes index 17fe4d7..6e45d34 100644 --- a/kubevirt.changes +++ b/kubevirt.changes @@ -1,3 +1,11 @@ +------------------------------------------------------------------- +Fri Jan 17 23:44:08 UTC 2025 - Caleb Crane + +- Fix guest-console-log failure during live migration and Harvester upgrades + 0001-feat-pass-timeout-from-virt-monitor-to-virt-tail.patch +- Fix SEV(ES) guests not being bootable from incompatible firmware + 0002-Ensure-SEV-VMs-use-stateless-OVMF-firmware.patch (bsc#1232762) + ------------------------------------------------------------------- Wed Nov 13 12:12:42 UTC 2024 - Vasily Ulyanov diff --git a/kubevirt.spec b/kubevirt.spec index 0698e31..6ef1b4d 100644 --- a/kubevirt.spec +++ b/kubevirt.spec @@ -1,7 +1,7 @@ # # spec file for package kubevirt # -# Copyright (c) 2024 SUSE LLC +# Copyright (c) 2025 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -41,6 +41,8 @@ Source1: kubevirt_containers_meta Source2: kubevirt_containers_meta.service Source3: %{url}/releases/download/v%{version}/disks-images-provider.yaml Source100: %{name}-rpmlintrc +Patch1: 0001-feat-pass-timeout-from-virt-monitor-to-virt-tail.patch +Patch2: 0002-Ensure-SEV-VMs-use-stateless-OVMF-firmware.patch BuildRequires: glibc-devel-static BuildRequires: golang-packaging BuildRequires: pkgconfig