builder/vmware: type the boot sequence

This commit is contained in:
Mitchell Hashimoto 2013-06-05 17:15:16 -07:00
parent 429ff62128
commit 6d610f1c6e
3 changed files with 102 additions and 1 deletions

View File

@ -51,6 +51,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook) packer.Artifact {
&stepCreateVMX{},
&stepHTTPServer{},
&stepRun{},
&stepTypeBootCommand{},
}
// Setup the state bag

View File

@ -41,7 +41,7 @@ func (s *stepRun) Run(state map[string]interface{}) multistep.StepAction {
// Wait the wait amount
if config.BootWait > 0 {
ui.Say(fmt.Sprintf("Waiting %d seconds for boot...", config.BootWait))
time.Sleep(config.BootWait * time.Second)
time.Sleep(time.Duration(config.BootWait) * time.Second)
}
return multistep.ActionContinue

View File

@ -0,0 +1,100 @@
package vmware
import (
"fmt"
"github.com/mitchellh/go-vnc"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
"log"
"net"
"strings"
"time"
"unicode"
"unicode/utf8"
)
const KeyLeftShift uint32 = 0xFFE1
// This step "types" the boot command into the VM over VNC.
//
// Uses:
// config *config
// ui packer.Ui
// vnc_port uint
//
// Produces:
// <nothing>
type stepTypeBootCommand struct{}
func (s *stepTypeBootCommand) Run(state map[string]interface{}) multistep.StepAction {
config := state["config"].(*config)
ui := state["ui"].(packer.Ui)
vncPort := state["vnc_port"].(uint)
ui.Say("Connecting to VM via VNC")
nc, err := net.Dial("tcp", fmt.Sprintf("127.0.0.1:%d", vncPort))
if err != nil {
ui.Error(fmt.Sprintf("Error connecting to VNC: %s", err))
return multistep.ActionHalt
}
defer nc.Close()
c, err := vnc.Client(nc, &vnc.ClientConfig{Exclusive: true})
if err != nil {
ui.Error(fmt.Sprintf("Error handshaking with VNC: %s", err))
return multistep.ActionHalt
}
defer c.Close()
log.Printf("Connecting to VNC desktop: %s", c.DesktopName)
ui.Say("Typing the boot command over VNC...")
for _, command := range config.BootCommand {
vncSendString(c, command)
}
return multistep.ActionContinue
}
func (*stepTypeBootCommand) Cleanup(map[string]interface{}) {}
func vncSendString(c *vnc.ClientConn, original string) {
special := make(map[string]uint32)
special["<enter>"] = 0xFF0D
special["<return>"] = 0xFF0D
special["<esc>"] = 0xFF1B
// TODO(mitchellh): Ripe for optimizations of some point, perhaps.
for len(original) > 0 {
var keyCode uint32
keyShift := false
for specialCode, specialValue := range special {
if strings.HasPrefix(original, specialCode) {
log.Printf("Special code '%s' found, replacing with: %d", specialCode, specialValue)
keyCode = specialValue
original = original[len(specialCode):]
break
}
}
if keyCode == 0 {
r, size := utf8.DecodeRuneInString(original)
original = original[size:]
keyCode = uint32(r)
keyShift = unicode.IsUpper(r)
log.Printf("Sending char '%c', code %d, shift %v", r, keyCode, keyShift)
}
if keyShift {
c.KeyEvent(KeyLeftShift, true)
}
c.KeyEvent(keyCode, true)
c.KeyEvent(keyCode, false)
if keyShift {
c.KeyEvent(KeyLeftShift, false)
}
}
}