diff --git a/qemu/qemu-kernel.go b/qemu/qemu-kernel.go index 6f8ee88..26683f0 100644 --- a/qemu/qemu-kernel.go +++ b/qemu/qemu-kernel.go @@ -5,6 +5,7 @@ package qemukernel import ( + "bytes" "errors" "fmt" "io" @@ -237,14 +238,19 @@ func (q *QemuSystem) Stop() { } } -// Command executes shell commands on qemu system -func (q *QemuSystem) Command(user, cmd string) (output string, err error) { +func (q QemuSystem) ssh(user string) (client *ssh.Client, err error) { cfg := &ssh.ClientConfig{ - User: user, + User: user, + HostKeyCallback: ssh.InsecureIgnoreHostKey(), } - cfg.HostKeyCallback = ssh.InsecureIgnoreHostKey() - client, err := ssh.Dial("tcp", q.sshAddrPort, cfg) + client, err = ssh.Dial("tcp", q.sshAddrPort, cfg) + return +} + +// Command executes shell commands on qemu system +func (q QemuSystem) Command(user, cmd string) (output string, err error) { + client, err := q.ssh(user) if err != nil { return } @@ -260,6 +266,23 @@ func (q *QemuSystem) Command(user, cmd string) (output string, err error) { return } +// AsyncCommand executes command on qemu system but does not wait for exit +func (q QemuSystem) AsyncCommand(user, cmd string) (err error) { + client, err := q.ssh(user) + if err != nil { + return + } + defer client.Close() + + session, err := client.NewSession() + if err != nil { + return + } + + return session.Run(fmt.Sprintf( + "nohup sh -c '%s' > /dev/null 2> /dev/null < /dev/null &", cmd)) +} + // CopyFile is copy file from local machine to remote through ssh/scp func (q *QemuSystem) CopyFile(user, localPath, remotePath string) (err error) { addrPort := strings.Split(q.sshAddrPort, ":") diff --git a/qemu/qemu-kernel_test.go b/qemu/qemu-kernel_test.go index 9e23bb2..d062ec0 100644 --- a/qemu/qemu-kernel_test.go +++ b/qemu/qemu-kernel_test.go @@ -96,7 +96,7 @@ func TestQemuSystemStart_Timeout(t *testing.T) { } } -func startTestQemu(t *testing.T) (q *QemuSystem, err error) { +func startTestQemu(t *testing.T, timeout time.Duration) (q *QemuSystem, err error) { t.Parallel() kernel := Kernel{ Name: "Test kernel", @@ -108,6 +108,10 @@ func startTestQemu(t *testing.T) (q *QemuSystem, err error) { return } + if timeout != 0 { + q.Timeout = timeout + } + if err = q.Start(); err != nil { return } @@ -116,7 +120,7 @@ func startTestQemu(t *testing.T) (q *QemuSystem, err error) { } func TestQemuSystemCommand(t *testing.T) { - qemu, err := startTestQemu(t) + qemu, err := startTestQemu(t, 0) if err != nil { t.Fatal(err) } @@ -145,7 +149,7 @@ func TestQemuSystemCommand(t *testing.T) { } func TestQemuSystemCopyFile(t *testing.T) { - qemu, err := startTestQemu(t) + qemu, err := startTestQemu(t, 0) if err != nil { t.Fatal(err) } @@ -177,7 +181,7 @@ func TestQemuSystemCopyFile(t *testing.T) { } func TestQemuSystemCopyAndRun(t *testing.T) { - qemu, err := startTestQemu(t) + qemu, err := startTestQemu(t, 0) if err != nil { t.Fatal(err) } @@ -210,7 +214,7 @@ func TestQemuSystemCopyAndRun(t *testing.T) { } func TestQemuSystemCopyAndInsmod(t *testing.T) { - qemu, err := startTestQemu(t) + qemu, err := startTestQemu(t, 0) if err != nil { t.Fatal(err) } @@ -235,3 +239,28 @@ func TestQemuSystemCopyAndInsmod(t *testing.T) { t.Fatal("insmod returns ok but there is no new kernel modules") } } + +func TestQemuSystemRun(t *testing.T) { + qemu, err := startTestQemu(t, 0) + if err != nil { + t.Fatal(err) + } + defer qemu.Stop() + + for { + _, err := qemu.Command("root", "echo") + if err == nil { + break + } + } + + start := time.Now() + err = qemu.AsyncCommand("root", "sleep 10s") + if err != nil { + t.Fatal(err) + } + if time.Since(start) > time.Second { + t.Fatalf("qemu.Run does not async (waited %s)", +time.Since(start)) + } + +}