@@ -40,11 +40,11 @@ import (
4040)
4141
4242const (
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+
368461func (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