diff --git a/builder/qemu/step_type_boot_command.go b/builder/qemu/step_type_boot_command.go index 7773053c9..af9334818 100644 --- a/builder/qemu/step_type_boot_command.go +++ b/builder/qemu/step_type_boot_command.go @@ -12,8 +12,10 @@ import ( "github.com/mitchellh/go-vnc" "github.com/mitchellh/multistep" + "github.com/mitchellh/packer/common" "github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/template/interpolate" + "os" ) const KeyLeftShift uint32 = 0xFFE1 @@ -146,6 +148,13 @@ func vncSendString(c *vnc.ClientConn, original string) { shiftedChars := "~!@#$%^&*()_+{}|:\"<>?" waitRe := regexp.MustCompile(`^`) + // We delay (default 100ms) between each key event to allow for CPU or + // network latency. See PackerKeyEnv for tuning. + keyInterval := common.PackerKeyDefault + if delay, err := time.ParseDuration(os.Getenv(common.PackerKeyEnv)); err == nil { + keyInterval = delay + } + // TODO(mitchellh): Ripe for optimizations of some point, perhaps. for len(original) > 0 { var keyCode uint32 @@ -157,11 +166,7 @@ func vncSendString(c *vnc.ClientConn, original string) { log.Printf("Special code '' found, replacing with: %d", keyCode) c.KeyEvent(keyCode, true) - time.Sleep(time.Second / 10) - - // qemu is picky, so no matter what, wait a small period - time.Sleep(100 * time.Millisecond) - + time.Sleep(keyInterval) continue } @@ -171,11 +176,7 @@ func vncSendString(c *vnc.ClientConn, original string) { log.Printf("Special code '' found, replacing with: %d", keyCode) c.KeyEvent(keyCode, true) - time.Sleep(time.Second / 10) - - // qemu is picky, so no matter what, wait a small period - time.Sleep(100 * time.Millisecond) - + time.Sleep(keyInterval) continue } @@ -185,11 +186,7 @@ func vncSendString(c *vnc.ClientConn, original string) { log.Printf("Special code '' found, replacing with: %d", keyCode) c.KeyEvent(keyCode, true) - time.Sleep(time.Second / 10) - - // qemu is picky, so no matter what, wait a small period - time.Sleep(100 * time.Millisecond) - + time.Sleep(keyInterval) continue } @@ -199,11 +196,7 @@ func vncSendString(c *vnc.ClientConn, original string) { log.Printf("Special code '' found, replacing with: %d", keyCode) c.KeyEvent(keyCode, false) - time.Sleep(time.Second / 10) - - // qemu is picky, so no matter what, wait a small period - time.Sleep(100 * time.Millisecond) - + time.Sleep(keyInterval) continue } @@ -213,11 +206,7 @@ func vncSendString(c *vnc.ClientConn, original string) { log.Printf("Special code '' found, replacing with: %d", keyCode) c.KeyEvent(keyCode, false) - time.Sleep(time.Second / 10) - - // qemu is picky, so no matter what, wait a small period - time.Sleep(100 * time.Millisecond) - + time.Sleep(keyInterval) continue } @@ -227,11 +216,7 @@ func vncSendString(c *vnc.ClientConn, original string) { log.Printf("Special code '' found, replacing with: %d", keyCode) c.KeyEvent(keyCode, false) - time.Sleep(time.Second / 10) - - // qemu is picky, so no matter what, wait a small period - time.Sleep(100 * time.Millisecond) - + time.Sleep(keyInterval) continue } @@ -241,11 +226,7 @@ func vncSendString(c *vnc.ClientConn, original string) { log.Printf("Special code '' found, replacing with: %d", keyCode) c.KeyEvent(keyCode, true) - time.Sleep(time.Second / 10) - - // qemu is picky, so no matter what, wait a small period - time.Sleep(100 * time.Millisecond) - + time.Sleep(keyInterval) continue } @@ -255,11 +236,7 @@ func vncSendString(c *vnc.ClientConn, original string) { log.Printf("Special code '' found, replacing with: %d", keyCode) c.KeyEvent(keyCode, true) - time.Sleep(time.Second / 10) - - // qemu is picky, so no matter what, wait a small period - time.Sleep(100 * time.Millisecond) - + time.Sleep(keyInterval) continue } @@ -269,11 +246,7 @@ func vncSendString(c *vnc.ClientConn, original string) { log.Printf("Special code '' found, replacing with: %d", keyCode) c.KeyEvent(keyCode, true) - time.Sleep(time.Second / 10) - - // qemu is picky, so no matter what, wait a small period - time.Sleep(100 * time.Millisecond) - + time.Sleep(keyInterval) continue } @@ -283,11 +256,7 @@ func vncSendString(c *vnc.ClientConn, original string) { log.Printf("Special code '' found, replacing with: %d", keyCode) c.KeyEvent(keyCode, false) - time.Sleep(time.Second / 10) - - // qemu is picky, so no matter what, wait a small period - time.Sleep(100 * time.Millisecond) - + time.Sleep(keyInterval) continue } @@ -297,11 +266,7 @@ func vncSendString(c *vnc.ClientConn, original string) { log.Printf("Special code '' found, replacing with: %d", keyCode) c.KeyEvent(keyCode, false) - time.Sleep(time.Second / 10) - - // qemu is picky, so no matter what, wait a small period - time.Sleep(100 * time.Millisecond) - + time.Sleep(keyInterval) continue } @@ -311,11 +276,7 @@ func vncSendString(c *vnc.ClientConn, original string) { log.Printf("Special code '' found, replacing with: %d", keyCode) c.KeyEvent(keyCode, false) - time.Sleep(time.Second / 10) - - // qemu is picky, so no matter what, wait a small period - time.Sleep(100 * time.Millisecond) - + time.Sleep(keyInterval) continue } @@ -373,15 +334,14 @@ func vncSendString(c *vnc.ClientConn, original string) { } c.KeyEvent(keyCode, true) - time.Sleep(time.Second / 10) + time.Sleep(keyInterval) + c.KeyEvent(keyCode, false) - time.Sleep(time.Second / 10) + time.Sleep(keyInterval) if keyShift { c.KeyEvent(KeyLeftShift, false) } - - // qemu is picky, so no matter what, wait a small period - time.Sleep(100 * time.Millisecond) + time.Sleep(keyInterval) } } diff --git a/builder/vmware/common/step_type_boot_command.go b/builder/vmware/common/step_type_boot_command.go index 99c08ed2c..b3cc02b79 100644 --- a/builder/vmware/common/step_type_boot_command.go +++ b/builder/vmware/common/step_type_boot_command.go @@ -4,6 +4,7 @@ import ( "fmt" "log" "net" + "os" "runtime" "strings" "time" @@ -12,6 +13,7 @@ import ( "github.com/mitchellh/go-vnc" "github.com/mitchellh/multistep" + "github.com/mitchellh/packer/common" "github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/template/interpolate" ) @@ -177,6 +179,13 @@ func vncSendString(c *vnc.ClientConn, original string) { shiftedChars := "~!@#$%^&*()_+{}|:\"<>?" + // We delay (default 100ms) between each key event to allow for CPU or + // network latency. See PackerKeyEnv for tuning. + keyInterval := common.PackerKeyDefault + if delay, err := time.ParseDuration(os.Getenv(common.PackerKeyEnv)); err == nil { + keyInterval = delay + } + // TODO(mitchellh): Ripe for optimizations of some point, perhaps. for len(original) > 0 { var keyCode uint32 @@ -188,7 +197,7 @@ func vncSendString(c *vnc.ClientConn, original string) { log.Printf("Special code '' found, replacing with: %d", keyCode) c.KeyEvent(keyCode, true) - time.Sleep(time.Second / 10) + time.Sleep(keyInterval) continue } @@ -199,7 +208,7 @@ func vncSendString(c *vnc.ClientConn, original string) { log.Printf("Special code '' found, replacing with: %d", keyCode) c.KeyEvent(keyCode, true) - time.Sleep(time.Second / 10) + time.Sleep(keyInterval) continue } @@ -210,7 +219,7 @@ func vncSendString(c *vnc.ClientConn, original string) { log.Printf("Special code '' found, replacing with: %d", keyCode) c.KeyEvent(keyCode, true) - time.Sleep(time.Second / 10) + time.Sleep(keyInterval) continue } @@ -221,7 +230,7 @@ func vncSendString(c *vnc.ClientConn, original string) { log.Printf("Special code '' found, replacing with: %d", keyCode) c.KeyEvent(keyCode, false) - time.Sleep(time.Second / 10) + time.Sleep(keyInterval) continue } @@ -232,7 +241,7 @@ func vncSendString(c *vnc.ClientConn, original string) { log.Printf("Special code '' found, replacing with: %d", keyCode) c.KeyEvent(keyCode, false) - time.Sleep(time.Second / 10) + time.Sleep(keyInterval) continue } @@ -243,7 +252,7 @@ func vncSendString(c *vnc.ClientConn, original string) { log.Printf("Special code '' found, replacing with: %d", keyCode) c.KeyEvent(keyCode, false) - time.Sleep(time.Second / 10) + time.Sleep(keyInterval) continue } @@ -254,7 +263,7 @@ func vncSendString(c *vnc.ClientConn, original string) { log.Printf("Special code '' found, replacing with: %d", keyCode) c.KeyEvent(keyCode, true) - time.Sleep(time.Second / 10) + time.Sleep(keyInterval) continue } @@ -265,7 +274,7 @@ func vncSendString(c *vnc.ClientConn, original string) { log.Printf("Special code '' found, replacing with: %d", keyCode) c.KeyEvent(keyCode, true) - time.Sleep(time.Second / 10) + time.Sleep(keyInterval) continue } @@ -276,7 +285,7 @@ func vncSendString(c *vnc.ClientConn, original string) { log.Printf("Special code '' found, replacing with: %d", keyCode) c.KeyEvent(keyCode, true) - time.Sleep(time.Second / 10) + time.Sleep(keyInterval) continue } @@ -287,7 +296,7 @@ func vncSendString(c *vnc.ClientConn, original string) { log.Printf("Special code '' found, replacing with: %d", keyCode) c.KeyEvent(keyCode, false) - time.Sleep(time.Second / 10) + time.Sleep(keyInterval) continue } @@ -298,7 +307,7 @@ func vncSendString(c *vnc.ClientConn, original string) { log.Printf("Special code '' found, replacing with: %d", keyCode) c.KeyEvent(keyCode, false) - time.Sleep(time.Second / 10) + time.Sleep(keyInterval) continue } @@ -309,7 +318,7 @@ func vncSendString(c *vnc.ClientConn, original string) { log.Printf("Special code '' found, replacing with: %d", keyCode) c.KeyEvent(keyCode, false) - time.Sleep(time.Second / 10) + time.Sleep(keyInterval) continue } @@ -357,13 +366,10 @@ func vncSendString(c *vnc.ClientConn, original string) { c.KeyEvent(KeyLeftShift, true) } - // Send the key events. We add a 100ms sleep after each key event - // to deal with network latency and the OS responding to the keystroke. - // It is kind of arbitrary but it is better than nothing. c.KeyEvent(keyCode, true) - time.Sleep(100 * time.Millisecond) + time.Sleep(keyInterval) c.KeyEvent(keyCode, false) - time.Sleep(100 * time.Millisecond) + time.Sleep(keyInterval) if keyShift { c.KeyEvent(KeyLeftShift, false) diff --git a/command/plugin.go b/command/plugin.go index 0c59c55b4..ffc3ad404 100644 --- a/command/plugin.go +++ b/command/plugin.go @@ -23,7 +23,7 @@ import ( dockerbuilder "github.com/mitchellh/packer/builder/docker" filebuilder "github.com/mitchellh/packer/builder/file" googlecomputebuilder "github.com/mitchellh/packer/builder/googlecompute" - hypervbuilder "github.com/mitchellh/packer/builder/hyperv/iso" + hypervisobuilder "github.com/mitchellh/packer/builder/hyperv/iso" nullbuilder "github.com/mitchellh/packer/builder/null" oneandonebuilder "github.com/mitchellh/packer/builder/oneandone" openstackbuilder "github.com/mitchellh/packer/builder/openstack" @@ -36,7 +36,6 @@ import ( virtualboxovfbuilder "github.com/mitchellh/packer/builder/virtualbox/ovf" vmwareisobuilder "github.com/mitchellh/packer/builder/vmware/iso" vmwarevmxbuilder "github.com/mitchellh/packer/builder/vmware/vmx" - amazonimportpostprocessor "github.com/mitchellh/packer/post-processor/amazon-import" artificepostprocessor "github.com/mitchellh/packer/post-processor/artifice" atlaspostprocessor "github.com/mitchellh/packer/post-processor/atlas" @@ -52,11 +51,11 @@ import ( vagrantpostprocessor "github.com/mitchellh/packer/post-processor/vagrant" vagrantcloudpostprocessor "github.com/mitchellh/packer/post-processor/vagrant-cloud" vspherepostprocessor "github.com/mitchellh/packer/post-processor/vsphere" - ansibleprovisioner "github.com/mitchellh/packer/provisioner/ansible" ansiblelocalprovisioner "github.com/mitchellh/packer/provisioner/ansible-local" chefclientprovisioner "github.com/mitchellh/packer/provisioner/chef-client" chefsoloprovisioner "github.com/mitchellh/packer/provisioner/chef-solo" + convergeprovisioner "github.com/mitchellh/packer/provisioner/converge" fileprovisioner "github.com/mitchellh/packer/provisioner/file" powershellprovisioner "github.com/mitchellh/packer/provisioner/powershell" puppetmasterlessprovisioner "github.com/mitchellh/packer/provisioner/puppet-masterless" @@ -83,7 +82,7 @@ var Builders = map[string]packer.Builder{ "docker": new(dockerbuilder.Builder), "file": new(filebuilder.Builder), "googlecompute": new(googlecomputebuilder.Builder), - "hyperv-iso": new(hypervbuilder.Builder), + "hyperv-iso": new(hypervisobuilder.Builder), "null": new(nullbuilder.Builder), "oneandone": new(oneandonebuilder.Builder), "openstack": new(openstackbuilder.Builder), @@ -103,6 +102,7 @@ var Provisioners = map[string]packer.Provisioner{ "ansible-local": new(ansiblelocalprovisioner.Provisioner), "chef-client": new(chefclientprovisioner.Provisioner), "chef-solo": new(chefsoloprovisioner.Provisioner), + "converge": new(convergeprovisioner.Provisioner), "file": new(fileprovisioner.Provisioner), "powershell": new(powershellprovisioner.Provisioner), "puppet-masterless": new(puppetmasterlessprovisioner.Provisioner), diff --git a/common/config.go b/common/config.go index e6c6477b5..cc7eced6a 100644 --- a/common/config.go +++ b/common/config.go @@ -7,8 +7,18 @@ import ( "path/filepath" "runtime" "strings" + "time" ) +// PackerKeyEnv is used to specify the key interval (delay) between keystrokes +// sent to the VM, typically in boot commands. This is to prevent host CPU +// utilization from causing key presses to be skipped or repeated incorrectly. +const PackerKeyEnv = "PACKER_KEY_INTERVAL" + +// PackerKeyDefault 100ms is appropriate for shared build infrastructure while a +// shorter delay (e.g. 10ms) can be used on a workstation. See PackerKeyEnv. +const PackerKeyDefault = 100 * time.Millisecond + // ScrubConfig is a helper that returns a string representation of // any struct with the given values stripped out. func ScrubConfig(target interface{}, values ...string) string { diff --git a/website/source/docs/builders/qemu.html.md b/website/source/docs/builders/qemu.html.md index 474cceafe..3d6e3323f 100644 --- a/website/source/docs/builders/qemu.html.md +++ b/website/source/docs/builders/qemu.html.md @@ -357,9 +357,15 @@ all typed in sequence. It is an array only to improve readability within the template. The boot command is "typed" character for character over a VNC connection to the -machine, simulating a human actually typing the keyboard. There are a set of -special keys available. If these are in your boot command, they will be replaced -by the proper key: +machine, simulating a human actually typing the keyboard. + +-> Keystrokes are typed as separate key up/down events over VNC with a + default 100ms delay. The delay alleviates issues with latency and CPU + contention. For local builds you can tune this delay by specifying + e.g. `PACKER_KEY_INTERVAL=10ms` to speed through the boot command. + +There are a set of special keys available. If these are in your boot +command, they will be replaced by the proper key: - `` - Backspace diff --git a/website/source/docs/builders/vmware-iso.html.md b/website/source/docs/builders/vmware-iso.html.md index 3a4bdaed0..b1c448da5 100644 --- a/website/source/docs/builders/vmware-iso.html.md +++ b/website/source/docs/builders/vmware-iso.html.md @@ -304,9 +304,15 @@ all typed in sequence. It is an array only to improve readability within the template. The boot command is "typed" character for character over a VNC connection to the -machine, simulating a human actually typing the keyboard. There are a set of -special keys available. If these are in your boot command, they will be replaced -by the proper key: +machine, simulating a human actually typing the keyboard. + +-> Keystrokes are typed as separate key up/down events over VNC with a + default 100ms delay. The delay alleviates issues with latency and CPU + contention. For local builds you can tune this delay by specifying + e.g. `PACKER_KEY_INTERVAL=10ms` to speed through the boot command. + +There are a set of special keys available. If these are in your boot +command, they will be replaced by the proper key: - `` - Backspace diff --git a/website/source/docs/builders/vmware-vmx.html.md b/website/source/docs/builders/vmware-vmx.html.md index 559a93e83..05eab33f5 100644 --- a/website/source/docs/builders/vmware-vmx.html.md +++ b/website/source/docs/builders/vmware-vmx.html.md @@ -185,9 +185,15 @@ all typed in sequence. It is an array only to improve readability within the template. The boot command is "typed" character for character over a VNC connection to the -machine, simulating a human actually typing the keyboard. There are a set of -special keys available. If these are in your boot command, they will be replaced -by the proper key: +machine, simulating a human actually typing the keyboard. + +-> Keystrokes are typed as separate key up/down events over VNC with a + default 100ms delay. The delay alleviates issues with latency and CPU + contention. For local builds you can tune this delay by specifying + e.g. `PACKER_KEY_INTERVAL=10ms` to speed through the boot command. + +There are a set of special keys available. If these are in your boot +command, they will be replaced by the proper key: - `` - Backspace