From a41de841570dfebb49c09852595176cf616c7cb6 Mon Sep 17 00:00:00 2001 From: Mikhail Klementev Date: Wed, 19 Sep 2018 06:13:28 +0000 Subject: [PATCH] Correct qemu arguments --- qemu-kernel.go | 68 ++++++++++++++++++++++++++++++++++++++++----- qemu-kernel_test.go | 26 ++++++++++++++--- 2 files changed, 83 insertions(+), 11 deletions(-) diff --git a/qemu-kernel.go b/qemu-kernel.go index 0738049..038a843 100644 --- a/qemu-kernel.go +++ b/qemu-kernel.go @@ -8,6 +8,8 @@ import ( "errors" "fmt" "io" + "math/rand" + "net" "os" "os/exec" "syscall" @@ -58,8 +60,12 @@ type Kernel struct { // QemuSystem describe qemu parameters and runned process type QemuSystem struct { - arch arch - kernel Kernel + arch arch + kernel Kernel + drivePath string + + Cpus int + Memory int // accessible while qemu is runned cmd *exec.Cmd @@ -76,7 +82,7 @@ type QemuSystem struct { } // NewQemuSystem constructor -func NewQemuSystem(arch arch, kernel Kernel) (q QemuSystem, err error) { +func NewQemuSystem(arch arch, kernel Kernel, drivePath string) (q QemuSystem, err error) { if _, err = exec.LookPath("qemu-system-" + string(arch)); err != nil { return } @@ -87,15 +93,63 @@ func NewQemuSystem(arch arch, kernel Kernel) (q QemuSystem, err error) { } q.kernel = kernel + if _, err = os.Stat(drivePath); err != nil { + return + } + q.drivePath = drivePath + + // Default values + q.Cpus = 2 + q.Memory = 512 // megabytes + return } +func getRandomAddrPort() (addr string) { + // 127.1-255.0-255.0-255:10000-50000 + ip := fmt.Sprintf("127.%d.%d.%d", + rand.Int()%254+1, rand.Int()%255, rand.Int()%254) + port := rand.Int()%40000 + 10000 + return fmt.Sprintf("%s:%d", ip, port) +} + +func getFreeAddrPort() (addrPort string) { + for { + addrPort = getRandomAddrPort() + ln, err := net.Listen("tcp", addrPort) + if err == nil { + ln.Close() + return + } + } +} + +func kvmExists() bool { + if _, err := os.Stat("/dev/kvm"); err != nil { + return false + } + return true +} + // Start qemu process func (q *QemuSystem) Start() (err error) { - q.cmd = exec.Command("qemu-system-"+string(q.arch), - // TODO - "-snapshot", - "-nographic") + rand.Seed(time.Now().UnixNano()) // Are you sure? + hostfwd := fmt.Sprintf("hostfwd=tcp:%s-:22", getFreeAddrPort()) + qemuArgs := []string{"-snapshot", "-nographic", + "-hda", q.drivePath, + "-kernel", q.kernel.Path, + "-append", "root=/dev/sda console=ttyS0 rw", + "-smp", fmt.Sprintf("%d", q.Cpus), + "-m", fmt.Sprintf("%d", q.Memory), + "-device", "e1000,netdev=n1", + "-netdev", "user,id=n1," + hostfwd, + } + + if (q.arch == X86_64 || q.arch == I386) && kvmExists() { + qemuArgs = append(qemuArgs, "-enable-kvm") + } + + q.cmd = exec.Command("qemu-system-"+string(q.arch), qemuArgs...) if q.pipe.stdin, err = q.cmd.StdinPipe(); err != nil { return diff --git a/qemu-kernel_test.go b/qemu-kernel_test.go index cd797b1..0ca4b3e 100644 --- a/qemu-kernel_test.go +++ b/qemu-kernel_test.go @@ -5,12 +5,13 @@ package qemukernel import ( + "net" "testing" ) func TestQemuSystemNew_InvalidKernelPath(t *testing.T) { kernel := Kernel{Name: "Invalid", Path: "/invalid/path"} - if _, err := NewQemuSystem(X86_64, kernel); err == nil { + if _, err := NewQemuSystem(X86_64, kernel, "/bin/sh"); err == nil { t.Fatal(err) } } @@ -18,7 +19,15 @@ func TestQemuSystemNew_InvalidKernelPath(t *testing.T) { func TestQemuSystemNew_InvalidQemuArch(t *testing.T) { // FIXME put kernel image to path not just "any valid path" kernel := Kernel{Name: "Valid path", Path: "/bin/sh"} - if _, err := NewQemuSystem(unsupported, kernel); err == nil { + if _, err := NewQemuSystem(unsupported, kernel, "/bin/sh"); err == nil { + t.Fatal(err) + } +} + +func TestQemuSystemNew_InvalidQemuDrivePath(t *testing.T) { + // FIXME put kernel image to path not just "any valid path" + kernel := Kernel{Name: "Valid path", Path: "/bin/sh"} + if _, err := NewQemuSystem(X86_64, kernel, "/invalid/path"); err == nil { t.Fatal(err) } } @@ -26,7 +35,7 @@ func TestQemuSystemNew_InvalidQemuArch(t *testing.T) { func TestQemuSystemNew(t *testing.T) { // FIXME put kernel image to path not just "any valid path" kernel := Kernel{Name: "Valid path", Path: "/bin/sh"} - if _, err := NewQemuSystem(X86_64, kernel); err != nil { + if _, err := NewQemuSystem(X86_64, kernel, "/bin/sh"); err != nil { t.Fatal(err) } } @@ -34,7 +43,7 @@ func TestQemuSystemNew(t *testing.T) { func TestQemuSystemStart(t *testing.T) { // TODO check kernel path on other distros than gentoo kernel := Kernel{Name: "Host kernel", Path: "/boot/vmlinuz-4.18.8"} - qemu, err := NewQemuSystem(X86_64, kernel) + qemu, err := NewQemuSystem(X86_64, kernel, "/bin/sh") if err != nil { t.Fatal(err) } @@ -45,3 +54,12 @@ func TestQemuSystemStart(t *testing.T) { qemu.Stop() } + +func TestGetFreeAddrPort(t *testing.T) { + addrPort := getFreeAddrPort() + ln, err := net.Listen("tcp", addrPort) + if err != nil { + t.Fatal(err) + } + ln.Close() +}