Skip to content

Commit 4894d85

Browse files
authored
Merge pull request #1539 from afbjorklund/qemu-version
Check qemu version in hostagent so not too old
2 parents e57ac78 + 2ff7d99 commit 4894d85

File tree

2 files changed

+78
-0
lines changed

2 files changed

+78
-0
lines changed

pkg/qemu/qemu.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"os/exec"
1010
"os/user"
1111
"path/filepath"
12+
"regexp"
1213
"runtime"
1314
"strconv"
1415
"strings"
@@ -36,6 +37,9 @@ type Config struct {
3637
SSHLocalPort int
3738
}
3839

40+
// MinimumQemuVersion is the minimum supported QEMU version
41+
const MinimumQemuVersion = "4.0.0"
42+
3943
// EnsureDisk also ensures the kernel and the initrd
4044
func EnsureDisk(cfg Config) error {
4145
diffDisk := filepath.Join(cfg.InstanceDir, filenames.DiffDisk)
@@ -341,6 +345,16 @@ func Cmdline(cfg Config) (string, []string, error) {
341345
return "", nil, err
342346
}
343347

348+
version, err := getQemuVersion(exe)
349+
if err != nil {
350+
logrus.WithError(err).Warning("Failed to detect QEMU version")
351+
} else {
352+
logrus.Debugf("QEMU version %s detected", version.String())
353+
if version.LessThan(*semver.New(MinimumQemuVersion)) {
354+
logrus.Fatalf("QEMU %v is too old, %v or later required", version, MinimumQemuVersion)
355+
}
356+
}
357+
344358
// Architecture
345359
accel := getAccel(*y.Arch)
346360
if !strings.Contains(string(features.AccelHelp), accel) {
@@ -717,6 +731,31 @@ func getAccel(arch limayaml.Arch) string {
717731
return "tcg"
718732
}
719733

734+
func parseQemuVersion(output string) (*semver.Version, error) {
735+
lines := strings.Split(output, "\n")
736+
regex := regexp.MustCompile(`^QEMU emulator version (\d+\.\d+\.\d+)`)
737+
matches := regex.FindStringSubmatch(lines[0])
738+
if len(matches) == 2 {
739+
return semver.New(matches[1]), nil
740+
}
741+
return &semver.Version{}, fmt.Errorf("failed to parse %v", output)
742+
}
743+
744+
func getQemuVersion(qemuExe string) (*semver.Version, error) {
745+
var (
746+
stdout bytes.Buffer
747+
stderr bytes.Buffer
748+
)
749+
cmd := exec.Command(qemuExe, "--version")
750+
cmd.Stdout = &stdout
751+
cmd.Stderr = &stderr
752+
if err := cmd.Run(); err != nil {
753+
return nil, fmt.Errorf("failed to run %v: stdout=%q, stderr=%q", cmd.Args, stdout.String(), stderr.String())
754+
}
755+
756+
return parseQemuVersion(stdout.String())
757+
}
758+
720759
func getFirmware(qemuExe string, arch limayaml.Arch) (string, error) {
721760
switch arch {
722761
case limayaml.X8664, limayaml.AARCH64:

pkg/qemu/qemu_test.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,42 @@ func TestArgValue(t *testing.T) {
4747
assert.Equal(t, tc.expectedOK, ok)
4848
}
4949
}
50+
51+
func TestParseQemuVersion(t *testing.T) {
52+
type testCase struct {
53+
versionOutput string
54+
expectedValue string
55+
expectedError string
56+
}
57+
testCases := []testCase{
58+
{
59+
// old one line version
60+
versionOutput: "QEMU emulator version 1.5.3 (qemu-kvm-1.5.3-175.el7_9.6), " +
61+
"Copyright (c) 2003-2008 Fabrice Bellard\n",
62+
expectedValue: "1.5.3",
63+
expectedError: "",
64+
},
65+
{
66+
// new two line version
67+
versionOutput: "QEMU emulator version 8.0.0 (v8.0.0)\n" +
68+
"Copyright (c) 2003-2022 Fabrice Bellard and the QEMU Project developers\n",
69+
expectedValue: "8.0.0",
70+
expectedError: "",
71+
},
72+
{
73+
versionOutput: "foobar",
74+
expectedValue: "0.0.0",
75+
expectedError: "failed to parse",
76+
},
77+
}
78+
79+
for _, tc := range testCases {
80+
v, err := parseQemuVersion(tc.versionOutput)
81+
if tc.expectedError == "" {
82+
assert.NilError(t, err)
83+
} else {
84+
assert.ErrorContains(t, err, tc.expectedError)
85+
}
86+
assert.Equal(t, tc.expectedValue, v.String())
87+
}
88+
}

0 commit comments

Comments
 (0)