-
Notifications
You must be signed in to change notification settings - Fork 0
/
driver.go
128 lines (101 loc) · 2.75 KB
/
driver.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package vmm
import (
"errors"
"io"
"os"
"os/exec"
"strings"
"time"
"github.com/hashicorp/packer/common/bootcommand"
"github.com/hashicorp/packer/packer"
)
var errNoTTY = errors.New("unable to determine instance tty")
// Driver describes a VMM driver.
type Driver interface {
bootcommand.BCDriver
CreateDisk(path, size string) error
Start(name string, args ...string) error
Stop(name string) error
}
// VmmDriver manages a vmm instance.
type VmmDriver struct {
doasPath string
logPath string
vmctlPath string
tty io.WriteCloser
ui packer.Ui
}
// CreateDisk creates a new disk image.
func (driver *VmmDriver) CreateDisk(path, size string) error {
args := []string{"create", path, "-s", size}
driver.ui.Message("Executing " + driver.vmctlPath + " " + strings.Join(args, " "))
return exec.Command(driver.vmctlPath, args...).Run()
}
// Start the VM and create a pipe to insert commands into the VM.
func (driver *VmmDriver) Start(name string, args ...string) error {
driver.ui.Message("Logging console output to " + driver.logPath)
logFile, err := os.Create(driver.logPath)
if err != nil {
return err
}
args = append([]string{driver.vmctlPath, "start", name}, args...)
driver.ui.Message("Executing " + driver.doasPath + " " + strings.Join(args, " "))
cmd := exec.Command(driver.doasPath, args...)
stdout, err := cmd.StdoutPipe()
if err != nil {
return err
}
// Create an stdin pipe that is used to issue commands.
if driver.tty, err = cmd.StdinPipe(); err != nil {
return err
}
// Write the console output to the log file.
go func() {
defer stdout.Close()
defer logFile.Close()
_, _ = io.Copy(logFile, stdout)
}()
// Start up the VM.
if err := cmd.Start(); err != nil {
return err
}
// Give the VM a bit of time to start up.
time.Sleep(3 * time.Second)
return nil
}
// Stop the VM and close down the input pipe.
func (driver *VmmDriver) Stop(name string) error {
driver.ui.Message("Executing " + driver.doasPath + " " + driver.vmctlPath + " stop " + name)
err := exec.Command(driver.doasPath, driver.vmctlPath, "stop", name).Run()
if err != nil {
return err
}
if driver.tty != nil {
return driver.tty.Close()
}
return nil
}
// SendKey sends a key press.
func (driver *VmmDriver) SendKey(key rune, action bootcommand.KeyAction) error {
data := []byte{byte(key)}
_, err := driver.tty.Write(data)
return err
}
// SendSpecial sends a special character.
func (driver *VmmDriver) SendSpecial(special string, action bootcommand.KeyAction) error {
var data []byte
switch special {
case "enter":
data = []byte("\n")
}
if len(data) != 0 {
if _, err := driver.tty.Write(data); err != nil {
return err
}
}
return nil
}
// Flush doesn't do anything here.
func (driver *VmmDriver) Flush() error {
return nil
}