Skip to content

Commit

Permalink
Merge pull request kubevirt#10036 from vasiliy-ul/fix-qemu-system-lookup
Browse files Browse the repository at this point in the history
Fix qemu-system-* process lookup
  • Loading branch information
kubevirt-bot authored Jul 10, 2023
2 parents e25174f + 7db1d95 commit 7697935
Show file tree
Hide file tree
Showing 9 changed files with 71 additions and 45 deletions.
6 changes: 3 additions & 3 deletions pkg/virt-handler/isolation/detector.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/virt-handler/isolation/detector_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
17 changes: 12 additions & 5 deletions pkg/virt-handler/isolation/process.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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
}
}
Expand Down
20 changes: 10 additions & 10 deletions pkg/virt-handler/isolation/process_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,33 +57,33 @@ 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",
testProcesses, "",
),
)

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,
),
)
Expand Down
1 change: 1 addition & 0 deletions tests/realtime/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
28 changes: 17 additions & 11 deletions tests/realtime/realtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package realtime

import (
"context"
"path/filepath"
"strconv"
"strings"

Expand All @@ -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"
)

Expand Down Expand Up @@ -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() {
Expand All @@ -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")
Expand All @@ -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), " ")
Expand All @@ -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")
Expand All @@ -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")
Expand Down
14 changes: 7 additions & 7 deletions tests/security_features_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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{})
Expand Down Expand Up @@ -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())
Expand All @@ -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")
Expand Down
16 changes: 12 additions & 4 deletions tests/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -374,10 +374,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,
Expand All @@ -394,14 +394,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"))
Expand Down Expand Up @@ -1772,6 +1772,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{})
Expand Down
12 changes: 8 additions & 4 deletions tests/vmi_configuration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2574,18 +2574,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))
Expand Down

0 comments on commit 7697935

Please sign in to comment.