Skip to content

Commit c0e53d4

Browse files
committed
go: add a new API for configuring serial ports
The previous API didn't allow us to disable the PTY but keep the ring buffer, for example. These should be orthogonal, so add a new API and deprecate the old one. Signed-off-by: David Scott <dave@recoil.org>
1 parent 9d53b94 commit c0e53d4

File tree

1 file changed

+106
-22
lines changed

1 file changed

+106
-22
lines changed

go/hyperkit.go

Lines changed: 106 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,11 @@ import (
4040
)
4141

4242
const (
43-
// ConsoleStdio configures console to use Stdio
43+
// ConsoleStdio configures console to use Stdio (deprecated)
4444
ConsoleStdio = iota
45-
// ConsoleFile configures console to a tty and output to a file
45+
// ConsoleFile configures console to a tty and output to a file (deprecated)
4646
ConsoleFile
47-
// ConsoleLog configures console to a tty and sends its contents to the logs
47+
// ConsoleLog configures console to a tty and sends its contents to the logs (deprecated)
4848
ConsoleLog
4949

5050
legacyVPNKitSock = "Library/Containers/com.docker.docker/Data/s50"
@@ -120,9 +120,13 @@ type HyperKit struct {
120120
// Memory is the amount of megabytes of memory for the VM.
121121
Memory int `json:"memory"`
122122

123-
// Console defines where the console of the VM should be connected to.
123+
// Console defines where the console of the VM should be connected to. (deprecated)
124124
Console int `json:"console"`
125125

126+
// Serials defines what happens to the I/O on the serial ports. If this is not nil
127+
// it overrides the Console setting.
128+
Serials []Serial `json:"serials"`
129+
126130
// Below here are internal members, but they are exported so
127131
// that they are written to the state json file, if configured.
128132

@@ -136,6 +140,28 @@ type HyperKit struct {
136140
process *os.Process
137141
}
138142

143+
// Serial port.
144+
type Serial struct {
145+
// InteractiveConsole allows a user to connect to a live VM serial console.
146+
InteractiveConsole InteractiveConsole
147+
// LogToRingBuffer will write console output to a fixed size ring buffer file.
148+
LogToRingBuffer bool
149+
// LogToASL will write console output to the Apple System Log.
150+
LogToASL bool
151+
}
152+
153+
// InteractiveConsole is an optional interactive VM console.
154+
type InteractiveConsole int
155+
156+
const (
157+
// NoInteractiveConsole disables the interactive console.
158+
NoInteractiveConsole = InteractiveConsole(iota)
159+
// StdioInteractiveConsole creates a console on stdio.
160+
StdioInteractiveConsole
161+
// TTYInteractiveConsole creates a console on a TTY.
162+
TTYInteractiveConsole
163+
)
164+
139165
// New creates a template config structure.
140166
// - If hyperkit can't be found an error is returned.
141167
// - If vpnkitsock is empty no networking is configured. If it is set
@@ -196,11 +222,7 @@ func (h *HyperKit) Start(cmdline string) (chan error, error) {
196222
return errCh, nil
197223
}
198224

199-
// check validates `h`. It also creates the disks if needed.
200-
func (h *HyperKit) check() error {
201-
log.Debugf("hyperkit: check %#v", h)
202-
var err error
203-
// Sanity checks on configuration
225+
func (h *HyperKit) checkLegacyConsole() error {
204226
switch h.Console {
205227
case ConsoleFile, ConsoleLog:
206228
if h.StateDir == "" {
@@ -211,6 +233,41 @@ func (h *HyperKit) check() error {
211233
return fmt.Errorf("If ConsoleStdio is set but stdio is not a terminal, StateDir must be specified")
212234
}
213235
}
236+
return nil
237+
}
238+
239+
func (h *HyperKit) checkSerials() error {
240+
for _, serial := range h.Serials {
241+
if serial.LogToRingBuffer && h.StateDir == "" {
242+
return fmt.Errorf("If VM is to log to a ring buffer, StateDir must be specified")
243+
}
244+
if serial.InteractiveConsole == StdioInteractiveConsole && !isTerminal(os.Stdout) {
245+
return fmt.Errorf("If StdioInteractiveConsole is set, stdio must be a TTY")
246+
}
247+
if serial.InteractiveConsole == TTYInteractiveConsole && h.StateDir == "" {
248+
return fmt.Errorf("If TTYInteractiveConsole is set, StateDir must be specified ")
249+
}
250+
if serial.LogToRingBuffer && h.StateDir == "" {
251+
return fmt.Errorf("If LogToRingBuffer is set, StateDir must be specified")
252+
}
253+
}
254+
return nil
255+
}
256+
257+
// check validates `h`. It also creates the disks if needed.
258+
func (h *HyperKit) check() error {
259+
log.Debugf("hyperkit: check %#v", h)
260+
var err error
261+
// Sanity checks on configuration
262+
if h.Serials == nil {
263+
if err := h.checkLegacyConsole(); err != nil {
264+
return err
265+
}
266+
} else {
267+
if err := h.checkSerials(); err != nil {
268+
return err
269+
}
270+
}
214271
for _, image := range h.ISOImages {
215272
if _, err = os.Stat(image); os.IsNotExist(err) {
216273
return fmt.Errorf("ISO %s does not exist", image)
@@ -365,6 +422,42 @@ func intArrayToString(i []int, sep string) string {
365422
return strings.Join(s, sep)
366423
}
367424

425+
func (h *HyperKit) legacyConsoleArgs() []string {
426+
cfg := "com1"
427+
if h.Console == ConsoleStdio && isTerminal(os.Stdout) {
428+
cfg += fmt.Sprintf(",stdio")
429+
} else {
430+
cfg += fmt.Sprintf(",autopty=%s/tty", h.StateDir)
431+
}
432+
if h.Console == ConsoleLog {
433+
cfg += fmt.Sprintf(",asl")
434+
} else {
435+
cfg += fmt.Sprintf(",log=%s/console-ring", h.StateDir)
436+
}
437+
return []string{"-l", cfg}
438+
}
439+
440+
func (h *HyperKit) serialArgs() []string {
441+
results := []string{}
442+
for i, serial := range h.Serials {
443+
cfg := fmt.Sprintf("com%d", i+1)
444+
switch serial.InteractiveConsole {
445+
case StdioInteractiveConsole:
446+
cfg += fmt.Sprintf(",stdio")
447+
case TTYInteractiveConsole:
448+
cfg += fmt.Sprintf(",autopty=%s/tty", h.StateDir)
449+
}
450+
if serial.LogToASL {
451+
cfg += fmt.Sprintf(",asl")
452+
}
453+
if serial.LogToRingBuffer {
454+
cfg += fmt.Sprintf(",log=%s/console-ring", h.StateDir)
455+
}
456+
results = append(results, "-l", cfg)
457+
}
458+
return results
459+
}
460+
368461
func (h *HyperKit) buildArgs(cmdline string) {
369462
a := []string{"-A", "-u"}
370463
if h.StateDir != "" {
@@ -429,19 +522,10 @@ func (h *HyperKit) buildArgs(cmdline string) {
429522
}
430523

431524
// -l: LPC device configuration.
432-
{
433-
cfg := "com1"
434-
if h.Console == ConsoleStdio && isTerminal(os.Stdout) {
435-
cfg += fmt.Sprintf(",stdio")
436-
} else {
437-
cfg += fmt.Sprintf(",autopty=%s/tty", h.StateDir)
438-
}
439-
if h.Console == ConsoleLog {
440-
cfg += fmt.Sprintf(",asl")
441-
} else {
442-
cfg += fmt.Sprintf(",log=%s/console-ring", h.StateDir)
443-
}
444-
a = append(a, "-l", cfg)
525+
if h.Serials == nil {
526+
a = append(a, h.legacyConsoleArgs()...)
527+
} else {
528+
a = append(a, h.serialArgs()...)
445529
}
446530

447531
if h.Bootrom == "" {

0 commit comments

Comments
 (0)