From 564c604e1f519b6e7cd8dc2e6a6d573e978b2df06904c24f8e0555255c381fb3 Mon Sep 17 00:00:00 2001 From: Vasily Ulyanov Date: Mon, 10 Jul 2023 11:33:01 +0000 Subject: [PATCH] Accepting request 1097920 from home:vulyanov:branches:Virtualization - Fix qemu-system- process lookup 0002-Fix-qemu-system-lookup.patch OBS-URL: https://build.opensuse.org/request/show/1097920 OBS-URL: https://build.opensuse.org/package/show/Virtualization/kubevirt?expand=0&rev=117 --- 0002-Fix-qemu-system-lookup.patch | 399 ++++++++++++++++++++++++++++++ kubevirt.changes | 6 + kubevirt.spec | 1 + 3 files changed, 406 insertions(+) create mode 100644 0002-Fix-qemu-system-lookup.patch diff --git a/0002-Fix-qemu-system-lookup.patch b/0002-Fix-qemu-system-lookup.patch new file mode 100644 index 0000000..046f77b --- /dev/null +++ b/0002-Fix-qemu-system-lookup.patch @@ -0,0 +1,399 @@ +From c4d429f3edffaaf8086f6cd22821b42ce2cf60c0 Mon Sep 17 00:00:00 2001 +From: Vasiliy Ulyanov +Date: Tue, 4 Jul 2023 13:27:25 +0200 +Subject: [PATCH 1/2] Lookup qemu process by executable prefix + +Exact matching with 'qemu-system' does not work since the executable +name also includes a suffix with current architecture, e.g. +qemu-system-x86_64. This leads to errors of type: + + no QEMU process found under process 16427 child processes + +Signed-off-by: Vasiliy Ulyanov +--- + pkg/virt-handler/isolation/detector.go | 6 +++--- + pkg/virt-handler/isolation/detector_test.go | 2 +- + pkg/virt-handler/isolation/process.go | 17 ++++++++++++----- + pkg/virt-handler/isolation/process_test.go | 20 ++++++++++---------- + 4 files changed, 26 insertions(+), 19 deletions(-) + +diff --git a/pkg/virt-handler/isolation/detector.go b/pkg/virt-handler/isolation/detector.go +index 62f920025..a90281824 100644 +--- a/pkg/virt-handler/isolation/detector.go ++++ b/pkg/virt-handler/isolation/detector.go +@@ -185,13 +185,13 @@ func AdjustQemuProcessMemoryLimits(podIsoDetector PodIsolationDetector, vmi *v1. + return nil + } + +-var qemuProcessExecutables = []string{"qemu-system", "qemu-kvm"} ++var qemuProcessExecutablePrefixes = []string{"qemu-system", "qemu-kvm"} + + // findIsolatedQemuProcess Returns the first occurrence of the QEMU process whose parent is PID" + func findIsolatedQemuProcess(processes []ps.Process, pid int) (ps.Process, error) { + processes = childProcesses(processes, pid) +- for _, exec := range qemuProcessExecutables { +- if qemuProcess := lookupProcessByExecutable(processes, exec); qemuProcess != nil { ++ for _, execPrefix := range qemuProcessExecutablePrefixes { ++ if qemuProcess := lookupProcessByExecutablePrefix(processes, execPrefix); qemuProcess != nil { + return qemuProcess, nil + } + } +diff --git a/pkg/virt-handler/isolation/detector_test.go b/pkg/virt-handler/isolation/detector_test.go +index 29486d00d..6ada37918 100644 +--- a/pkg/virt-handler/isolation/detector_test.go ++++ b/pkg/virt-handler/isolation/detector_test.go +@@ -132,7 +132,7 @@ var _ = Describe("findIsolatedQemuProcess", func() { + fakeProcess3} + + qemuKvmProc := ProcessStub{pid: 101, ppid: virtLauncherPid, binary: "qemu-kvm"} +- qemuSystemProc := ProcessStub{pid: 101, ppid: virtLauncherPid, binary: "qemu-system"} ++ qemuSystemProc := ProcessStub{pid: 101, ppid: virtLauncherPid, binary: "qemu-system-x86_64"} + + DescribeTable("should return QEMU process", + func(processes []ps.Process, pid int, expectedProcess ps.Process) { +diff --git a/pkg/virt-handler/isolation/process.go b/pkg/virt-handler/isolation/process.go +index bf3072153..6a99a4d52 100644 +--- a/pkg/virt-handler/isolation/process.go ++++ b/pkg/virt-handler/isolation/process.go +@@ -19,7 +19,11 @@ + + package isolation + +-import "github.com/mitchellh/go-ps" ++import ( ++ "strings" ++ ++ "github.com/mitchellh/go-ps" ++) + + // childProcesses given a list of processes, it returns the ones that are children + // of the given PID. +@@ -34,11 +38,14 @@ func childProcesses(processes []ps.Process, pid int) []ps.Process { + return childProcesses + } + +-// lookupProcessByExecutable given list of processes, it return the first occurrence +-// of a process that runs the given executable. +-func lookupProcessByExecutable(processes []ps.Process, exectutable string) ps.Process { ++// lookupProcessByExecutablePrefix given list of processes, it return the first occurrence ++// of a process with the given executable prefix. ++func lookupProcessByExecutablePrefix(processes []ps.Process, execPrefix string) ps.Process { ++ if execPrefix == "" { ++ return nil ++ } + for _, process := range processes { +- if process.Executable() == exectutable { ++ if strings.HasPrefix(process.Executable(), execPrefix) { + return process + } + } +diff --git a/pkg/virt-handler/isolation/process_test.go b/pkg/virt-handler/isolation/process_test.go +index de7d1449d..1a882e129 100644 +--- a/pkg/virt-handler/isolation/process_test.go ++++ b/pkg/virt-handler/isolation/process_test.go +@@ -57,17 +57,17 @@ var _ = Describe("process", func() { + ) + }) + +- Context("lookup process by executable", func() { ++ Context("lookup process by executable prefix", func() { + procStub5 := ProcessStub{ppid: 100, pid: 220, binary: processTestExecPath} + + DescribeTable("should find no process", +- func(processes []ps.Process, executable string) { +- Expect(lookupProcessByExecutable(processes, executable)).To(BeNil()) ++ func(processes []ps.Process, executablePrefix string) { ++ Expect(lookupProcessByExecutablePrefix(processes, executablePrefix)).To(BeNil()) + }, +- Entry("given no input processes and empty string as executable", ++ Entry("given no input processes and empty string as executable prefix", + emptyProcessList, "", + ), +- Entry("given no input processes and executable", ++ Entry("given no input processes and executable prefix", + emptyProcessList, "processA", + ), + Entry("given processes list and empty string", +@@ -75,15 +75,15 @@ var _ = Describe("process", func() { + ), + ) + +- DescribeTable("should return the first occurrence of a process that runs the given executable", +- func(processes []ps.Process, executable string, expectedProcess ps.Process) { +- Expect(lookupProcessByExecutable(processes, executable)). ++ DescribeTable("should return the first occurrence of a process with the given executable prefix", ++ func(processes []ps.Process, executablePrefix string, expectedProcess ps.Process) { ++ Expect(lookupProcessByExecutablePrefix(processes, executablePrefix)). + To(Equal(expectedProcess)) + }, +- Entry("given processes list that includes exactly one process that runs the executable", ++ Entry("given processes list that includes exactly one process with the executable prefix", + testProcesses, processTestExecPath, procStub1, + ), +- Entry("given processes list that includes more than one process that runs the executable", ++ Entry("given processes list that includes more than one process with the executable prefix", + append(testProcesses, procStub5), processTestExecPath, procStub1, + ), + ) +-- +2.41.0 + + +From 30a544b57182fff64646eede6eba360cd0ceb0c3 Mon Sep 17 00:00:00 2001 +From: Vasiliy Ulyanov +Date: Tue, 4 Jul 2023 14:04:57 +0200 +Subject: [PATCH 2/2] tests: Detect the qemu emulator binary in runtime + +Avoid hardcoding qemu-kvm since the underlying images may use e.g. +qemu-system-*. + +Signed-off-by: Vasiliy Ulyanov +--- + tests/realtime/BUILD.bazel | 1 + + tests/realtime/realtime.go | 28 +++++++++++++++++----------- + tests/security_features_test.go | 14 +++++++------- + tests/utils.go | 16 ++++++++++++---- + tests/vmi_configuration_test.go | 12 ++++++++---- + 5 files changed, 45 insertions(+), 26 deletions(-) + +diff --git a/tests/realtime/BUILD.bazel b/tests/realtime/BUILD.bazel +index 3718467e1..9d66eb7df 100644 +--- a/tests/realtime/BUILD.bazel ++++ b/tests/realtime/BUILD.bazel +@@ -18,6 +18,7 @@ go_library( + "//tests/framework/kubevirt:go_default_library", + "//tests/libvmi:go_default_library", + "//tests/libwait:go_default_library", ++ "//tests/testsuite:go_default_library", + "//tests/util:go_default_library", + "//vendor/github.com/onsi/ginkgo/v2:go_default_library", + "//vendor/github.com/onsi/gomega:go_default_library", +diff --git a/tests/realtime/realtime.go b/tests/realtime/realtime.go +index a9e93161c..0e1249f0d 100644 +--- a/tests/realtime/realtime.go ++++ b/tests/realtime/realtime.go +@@ -2,6 +2,7 @@ package realtime + + import ( + "context" ++ "path/filepath" + "strconv" + "strings" + +@@ -25,6 +26,7 @@ import ( + "kubevirt.io/kubevirt/tests/framework/kubevirt" + "kubevirt.io/kubevirt/tests/libvmi" + "kubevirt.io/kubevirt/tests/libwait" ++ "kubevirt.io/kubevirt/tests/testsuite" + "kubevirt.io/kubevirt/tests/util" + ) + +@@ -56,12 +58,12 @@ func newFedoraRealtime(realtimeMask string) *v1.VirtualMachineInstance { + ) + } + +-func byStartingTheVMI(vmi *v1.VirtualMachineInstance, virtClient kubecli.KubevirtClient) { ++func byStartingTheVMI(vmi *v1.VirtualMachineInstance, virtClient kubecli.KubevirtClient) *v1.VirtualMachineInstance { + By("Starting a VirtualMachineInstance") + var err error +- vmi, err = virtClient.VirtualMachineInstance(util.NamespaceTestDefault).Create(context.Background(), vmi) ++ vmi, err = virtClient.VirtualMachineInstance(testsuite.GetTestNamespace(vmi)).Create(context.Background(), vmi) + Expect(err).ToNot(HaveOccurred()) +- libwait.WaitForSuccessfulVMIStart(vmi) ++ return libwait.WaitForSuccessfulVMIStart(vmi) + } + + var _ = Describe("[sig-compute-realtime][Serial]Realtime", Serial, decorators.SigComputeRealtime, func() { +@@ -81,15 +83,17 @@ var _ = Describe("[sig-compute-realtime][Serial]Realtime", Serial, decorators.Si + + It("when no mask is specified", func() { + const noMask = "" +- vmi := newFedoraRealtime(noMask) +- byStartingTheVMI(vmi, virtClient) ++ vmi := byStartingTheVMI(newFedoraRealtime(noMask), virtClient) + By("Validating VCPU scheduler placement information") + pod := tests.GetRunningPodByVirtualMachineInstance(vmi, util.NamespaceTestDefault) ++ emulator, err := tests.GetRunningVMIEmulator(vmi) ++ Expect(err).ToNot(HaveOccurred()) ++ emulator = filepath.Base(emulator) + psOutput, err := exec.ExecuteCommandOnPod( + virtClient, + pod, + "compute", +- []string{tests.BinBash, "-c", "ps -LC qemu-kvm -o policy,rtprio,psr|grep FF| awk '{print $2}'"}, ++ []string{tests.BinBash, "-c", "ps -LC " + emulator + " -o policy,rtprio,psr|grep FF| awk '{print $2}'"}, + ) + Expect(err).ToNot(HaveOccurred()) + slice := strings.Split(strings.TrimSpace(psOutput), "\n") +@@ -102,7 +106,7 @@ var _ = Describe("[sig-compute-realtime][Serial]Realtime", Serial, decorators.Si + virtClient, + pod, + "compute", +- []string{tests.BinBash, "-c", "grep 'locked memory' /proc/$(ps -C qemu-kvm -o pid --noheader|xargs)/limits |tr -s ' '| awk '{print $4\" \"$5}'"}, ++ []string{tests.BinBash, "-c", "grep 'locked memory' /proc/$(ps -C " + emulator + " -o pid --noheader|xargs)/limits |tr -s ' '| awk '{print $4\" \"$5}'"}, + ) + Expect(err).ToNot(HaveOccurred()) + limits := strings.Split(strings.TrimSpace(psOutput), " ") +@@ -123,15 +127,17 @@ var _ = Describe("[sig-compute-realtime][Serial]Realtime", Serial, decorators.Si + }) + + It("when realtime mask is specified", func() { +- vmi := newFedoraRealtime("0-1,^1") +- byStartingTheVMI(vmi, virtClient) ++ vmi := byStartingTheVMI(newFedoraRealtime("0-1,^1"), virtClient) + pod := tests.GetRunningPodByVirtualMachineInstance(vmi, util.NamespaceTestDefault) + By("Validating VCPU scheduler placement information") ++ emulator, err := tests.GetRunningVMIEmulator(vmi) ++ Expect(err).ToNot(HaveOccurred()) ++ emulator = filepath.Base(emulator) + psOutput, err := exec.ExecuteCommandOnPod( + virtClient, + pod, + "compute", +- []string{tests.BinBash, "-c", "ps -LC qemu-kvm -o policy,rtprio,psr|grep FF| awk '{print $2}'"}, ++ []string{tests.BinBash, "-c", "ps -LC " + emulator + " -o policy,rtprio,psr|grep FF| awk '{print $2}'"}, + ) + Expect(err).ToNot(HaveOccurred()) + slice := strings.Split(strings.TrimSpace(psOutput), "\n") +@@ -143,7 +149,7 @@ var _ = Describe("[sig-compute-realtime][Serial]Realtime", Serial, decorators.Si + virtClient, + pod, + "compute", +- []string{tests.BinBash, "-c", "ps -TcC qemu-kvm |grep CPU |awk '{print $3\" \" $8}'"}, ++ []string{tests.BinBash, "-c", "ps -TcC " + emulator + " |grep CPU |awk '{print $3\" \" $8}'"}, + ) + Expect(err).ToNot(HaveOccurred()) + slice = strings.Split(strings.TrimSpace(psOutput), "\n") +diff --git a/tests/security_features_test.go b/tests/security_features_test.go +index cc49ba038..42adfe1d6 100644 +--- a/tests/security_features_test.go ++++ b/tests/security_features_test.go +@@ -129,9 +129,9 @@ var _ = Describe("[Serial][sig-compute]SecurityFeatures", Serial, decorators.Sig + Expect(err).ToNot(HaveOccurred()) + libwait.WaitForSuccessfulVMIStart(vmi) + +- domSpec, err := tests.GetRunningVMIDomainSpec(vmi) ++ emulator, err := tests.GetRunningVMIEmulator(vmi) + Expect(err).ToNot(HaveOccurred()) +- emulator := "[/]" + strings.TrimPrefix(domSpec.Devices.Emulator, "/") ++ emulator = "[/]" + strings.TrimPrefix(emulator, "/") + + pod := tests.GetRunningPodByVirtualMachineInstance(vmi, testsuite.GetTestNamespace(vmi)) + qemuProcessSelinuxContext, err := exec.ExecuteCommandOnPod( +@@ -142,10 +142,10 @@ var _ = Describe("[Serial][sig-compute]SecurityFeatures", Serial, decorators.Sig + ) + Expect(err).ToNot(HaveOccurred()) + +- By("Checking that qemu-kvm process is of the SELinux type container_t") ++ By("Checking that qemu process is of the SELinux type container_t") + Expect(strings.Split(qemuProcessSelinuxContext, ":")[2]).To(Equal("container_t")) + +- By("Checking that qemu-kvm process has SELinux category_set") ++ By("Checking that qemu process has SELinux category_set") + Expect(strings.Split(qemuProcessSelinuxContext, ":")).To(HaveLen(5)) + + err = virtClient.VirtualMachineInstance(testsuite.GetTestNamespace(vmi)).Delete(context.Background(), vmi.Name, &metav1.DeleteOptions{}) +@@ -205,9 +205,9 @@ var _ = Describe("[Serial][sig-compute]SecurityFeatures", Serial, decorators.Sig + libwait.WaitUntilVMIReady(vmi, console.LoginToAlpine) + + By("Fetching virt-launcher Pod") +- domSpec, err := tests.GetRunningVMIDomainSpec(vmi) ++ emulator, err := tests.GetRunningVMIEmulator(vmi) + Expect(err).ToNot(HaveOccurred()) +- emulator := "[/]" + strings.TrimPrefix(domSpec.Devices.Emulator, "/") ++ emulator = "[/]" + strings.TrimPrefix(emulator, "/") + + pod, err := libvmi.GetPodByVirtualMachineInstance(vmi, testsuite.NamespacePrivileged) + Expect(err).ToNot(HaveOccurred()) +@@ -219,7 +219,7 @@ var _ = Describe("[Serial][sig-compute]SecurityFeatures", Serial, decorators.Sig + ) + Expect(err).ToNot(HaveOccurred()) + +- By("Checking that qemu-kvm process is of the SELinux type virt_launcher.process") ++ By("Checking that qemu process is of the SELinux type virt_launcher.process") + Expect(strings.Split(qemuProcessSelinuxContext, ":")[2]).To(Equal(launcherType)) + + By("Verifying SELinux context contains custom type in pod") +diff --git a/tests/utils.go b/tests/utils.go +index 6b5ab7de8..276046454 100644 +--- a/tests/utils.go ++++ b/tests/utils.go +@@ -363,10 +363,10 @@ func GetProcessName(pod *k8sv1.Pod, pid string) (output string, err error) { + return + } + +-func GetVcpuMask(pod *k8sv1.Pod, cpu string) (output string, err error) { ++func GetVcpuMask(pod *k8sv1.Pod, emulator, cpu string) (output string, err error) { + virtClient := kubevirt.Client() + +- pscmd := "ps -LC qemu-kvm -o lwp,comm| grep \"CPU " + cpu + "\" | cut -f 1 -d \"C\"" ++ pscmd := "ps -LC " + emulator + " -o lwp,comm| grep \"CPU " + cpu + "\" | cut -f 1 -d \"C\"" + output, err = exec.ExecuteCommandOnPod( + virtClient, + pod, +@@ -383,14 +383,14 @@ func GetVcpuMask(pod *k8sv1.Pod, cpu string) (output string, err error) { + return output, err + } + +-func GetKvmPitMask(pod *k8sv1.Pod, nodeName string) (output string, err error) { ++func GetKvmPitMask(pod *k8sv1.Pod, emulator, nodeName string) (output string, err error) { + virtClient := kubevirt.Client() + + output, err = exec.ExecuteCommandOnPod( + virtClient, + pod, + "compute", +- []string{"ps", "-C", "qemu-kvm", "-o", "pid", "--noheader"}, ++ []string{"ps", "-C", emulator, "-o", "pid", "--noheader"}, + ) + Expect(err).ToNot(HaveOccurred()) + qemupid := strings.TrimSpace(strings.Trim(output, "\n")) +@@ -1748,6 +1748,14 @@ func GetRunningVMIDomainSpec(vmi *v1.VirtualMachineInstance) (*launcherApi.Domai + return &runningVMISpec, err + } + ++func GetRunningVMIEmulator(vmi *v1.VirtualMachineInstance) (string, error) { ++ domSpec, err := GetRunningVMIDomainSpec(vmi) ++ if err != nil { ++ return "", err ++ } ++ return domSpec.Devices.Emulator, nil ++} ++ + func ForwardPorts(pod *k8sv1.Pod, ports []string, stop chan struct{}, readyTimeout time.Duration) error { + errChan := make(chan error, 1) + readyChan := make(chan struct{}) +diff --git a/tests/vmi_configuration_test.go b/tests/vmi_configuration_test.go +index cfdd1afe1..a574a911d 100644 +--- a/tests/vmi_configuration_test.go ++++ b/tests/vmi_configuration_test.go +@@ -2506,18 +2506,22 @@ var _ = Describe("[sig-compute]Configurations", decorators.SigCompute, func() { + &expect.BExp{R: "2"}, + }, 15)).To(Succeed()) + ++ emulator, err := tests.GetRunningVMIEmulator(vmi) ++ Expect(err).ToNot(HaveOccurred()) ++ emulator = filepath.Base(emulator) ++ + virtClient := kubevirt.Client() +- pscmd := []string{"ps", "-C", "qemu-kvm", "-o", "pid", "--noheader"} ++ pscmd := []string{"ps", "-C", emulator, "-o", "pid", "--noheader"} + _, err = exec.ExecuteCommandOnPod( + virtClient, readyPod, "compute", pscmd) +- // do not check for kvm-pit thread if qemu-kvm is not in use ++ // do not check for kvm-pit thread if qemu is not in use + if err != nil { + return + } +- kvmpitmask, err := tests.GetKvmPitMask(readyPod, node) ++ kvmpitmask, err := tests.GetKvmPitMask(readyPod, emulator, node) + Expect(err).ToNot(HaveOccurred()) + +- vcpuzeromask, err := tests.GetVcpuMask(readyPod, "0") ++ vcpuzeromask, err := tests.GetVcpuMask(readyPod, emulator, "0") + Expect(err).ToNot(HaveOccurred()) + + Expect(kvmpitmask).To(Equal(vcpuzeromask)) +-- +2.41.0 + diff --git a/kubevirt.changes b/kubevirt.changes index ff792e9..4afc8b4 100644 --- a/kubevirt.changes +++ b/kubevirt.changes @@ -1,3 +1,9 @@ +------------------------------------------------------------------- +Mon Jul 10 11:19:52 UTC 2023 - Vasily Ulyanov + +- Fix qemu-system- process lookup + 0002-Fix-qemu-system-lookup.patch + ------------------------------------------------------------------- Wed Jun 21 05:24:13 UTC 2023 - Vasily Ulyanov diff --git a/kubevirt.spec b/kubevirt.spec index 201313a..d892eb7 100644 --- a/kubevirt.spec +++ b/kubevirt.spec @@ -29,6 +29,7 @@ Source2: kubevirt_containers_meta.service Source3: %{url}/releases/download/v%{version}/disks-images-provider.yaml Source100: %{name}-rpmlintrc Patch0: 0001-Vulnerability-fix-limit-operator-secrets-permission.patch +Patch1: 0002-Fix-qemu-system-lookup.patch BuildRequires: glibc-devel-static BuildRequires: golang-packaging BuildRequires: pkgconfig